Replace native date/time inputs with DatePicker across calendar and todo forms

- EventForm + EventDetailPanel: native <Input type=date|datetime-local> → DatePicker with dynamic mode via all_day toggle
- TodoForm + TodoDetailPanel: merge date + time into single datetime DatePicker, remove separate time input, move recurrence select into 2-col grid beside date picker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-03-03 16:43:14 +08:00
parent e20c04ac4f
commit 6cd648f3a8
4 changed files with 53 additions and 59 deletions

View File

@ -13,6 +13,7 @@ import { formatUpdatedAt } from '@/components/shared/utils';
import CopyableField from '@/components/shared/CopyableField'; import CopyableField from '@/components/shared/CopyableField';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Select } from '@/components/ui/select'; import { Select } from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
@ -633,22 +634,24 @@ export default function EventDetailPanel({
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div className="space-y-1"> <div className="space-y-1">
<Label htmlFor="panel-start" required>Start</Label> <Label htmlFor="panel-start" required>Start</Label>
<Input <DatePicker
variant="input"
id="panel-start" id="panel-start"
type={editState.all_day ? 'date' : 'datetime-local'} mode={editState.all_day ? 'date' : 'datetime'}
value={editState.start_datetime} value={editState.start_datetime}
onChange={(e) => updateField('start_datetime', e.target.value)} onChange={(v) => updateField('start_datetime', v)}
className="text-xs" className="text-xs"
required required
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<Label htmlFor="panel-end">End</Label> <Label htmlFor="panel-end">End</Label>
<Input <DatePicker
variant="input"
id="panel-end" id="panel-end"
type={editState.all_day ? 'date' : 'datetime-local'} mode={editState.all_day ? 'date' : 'datetime'}
value={editState.end_datetime} value={editState.end_datetime}
onChange={(e) => updateField('end_datetime', e.target.value)} onChange={(v) => updateField('end_datetime', v)}
className="text-xs" className="text-xs"
/> />
</div> </div>

View File

@ -13,6 +13,7 @@ import {
SheetClose, SheetClose,
} from '@/components/ui/sheet'; } from '@/components/ui/sheet';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Select } from '@/components/ui/select'; import { Select } from '@/components/ui/select';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
@ -281,22 +282,24 @@ export default function EventForm({ event, templateData, templateName, initialSt
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="start" required>Start</Label> <Label htmlFor="start" required>Start</Label>
<Input <DatePicker
variant="input"
id="start" id="start"
type={formData.all_day ? 'date' : 'datetime-local'} mode={formData.all_day ? 'date' : 'datetime'}
value={formData.start_datetime} value={formData.start_datetime}
onChange={(e) => setFormData({ ...formData, start_datetime: e.target.value })} onChange={(v) => setFormData({ ...formData, start_datetime: v })}
required required
/> />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="end">End</Label> <Label htmlFor="end">End</Label>
<Input <DatePicker
variant="input"
id="end" id="end"
type={formData.all_day ? 'date' : 'datetime-local'} mode={formData.all_day ? 'date' : 'datetime'}
value={formData.end_datetime} value={formData.end_datetime}
onChange={(e) => setFormData({ ...formData, end_datetime: e.target.value })} onChange={(v) => setFormData({ ...formData, end_datetime: v })}
/> />
</div> </div>
</div> </div>

View File

@ -389,38 +389,31 @@ export default function TodoDetailPanel({
<DatePicker <DatePicker
variant="input" variant="input"
id="todo-due-date" id="todo-due-date"
value={editState.due_date} mode="datetime"
onChange={(v) => updateField('due_date', v)} value={editState.due_date ? (editState.due_date + 'T' + (editState.due_time || '00:00')) : ''}
onChange={(v) => {
updateField('due_date', v ? v.slice(0, 10) : '');
updateField('due_time', v ? v.slice(11, 16) : '');
}}
className="text-xs" className="text-xs"
/> />
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<Label htmlFor="todo-due-time">Due Time</Label> <Label htmlFor="todo-recurrence">Recurrence</Label>
<Input <Select
id="todo-due-time" id="todo-recurrence"
type="time" value={editState.recurrence_rule}
value={editState.due_time} onChange={(e) => updateField('recurrence_rule', e.target.value)}
onChange={(e) => updateField('due_time', e.target.value)}
className="text-xs" className="text-xs"
/> >
<option value="">None</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</Select>
</div> </div>
</div> </div>
<div className="space-y-1">
<Label htmlFor="todo-recurrence">Recurrence</Label>
<Select
id="todo-recurrence"
value={editState.recurrence_rule}
onChange={(e) => updateField('recurrence_rule', e.target.value)}
className="text-xs"
>
<option value="">None</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</Select>
</div>
{/* Save / Cancel at bottom */} {/* Save / Cancel at bottom */}
<div className="flex items-center justify-end gap-2 pt-2 border-t border-border"> <div className="flex items-center justify-end gap-2 pt-2 border-t border-border">
<Button variant="outline" size="sm" onClick={handleEditCancel}> <Button variant="outline" size="sm" onClick={handleEditCancel}>

View File

@ -133,35 +133,30 @@ export default function TodoForm({ todo, onClose }: TodoFormProps) {
<DatePicker <DatePicker
variant="input" variant="input"
id="due_date" id="due_date"
value={formData.due_date} mode="datetime"
onChange={(v) => setFormData({ ...formData, due_date: v })} value={formData.due_date ? (formData.due_date + 'T' + (formData.due_time || '00:00')) : ''}
onChange={(v) => setFormData({
...formData,
due_date: v ? v.slice(0, 10) : '',
due_time: v ? v.slice(11, 16) : '',
})}
/> />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="due_time">Due Time</Label> <Label htmlFor="recurrence">Recurrence</Label>
<Input <Select
id="due_time" id="recurrence"
type="time" value={formData.recurrence_rule}
value={formData.due_time} onChange={(e) => setFormData({ ...formData, recurrence_rule: e.target.value })}
onChange={(e) => setFormData({ ...formData, due_time: e.target.value })} >
/> <option value="">None</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</Select>
</div> </div>
</div> </div>
<div className="space-y-2">
<Label htmlFor="recurrence">Recurrence</Label>
<Select
id="recurrence"
value={formData.recurrence_rule}
onChange={(e) => setFormData({ ...formData, recurrence_rule: e.target.value })}
>
<option value="">None</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
</Select>
</div>
</div> </div>
<SheetFooter> <SheetFooter>