mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
add: tasks func()
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* File Name : DeadlinePicker.jsx
|
||||
* Type : Reusable Component
|
||||
* Description : Combined date + time picker for deadline fields.
|
||||
* Controlled via a single ISO datetime string (value / onChange).
|
||||
* Date is picked via a Calendar popover; time via a plain time input.
|
||||
*
|
||||
* Props:
|
||||
* value : string | null — ISO datetime string e.g. "2026-06-01T10:30"
|
||||
* onChange : (iso: string | null) => void
|
||||
* disabled?: boolean
|
||||
***********************************************************************************************************************************************************************/
|
||||
import { useState } from 'react';
|
||||
import { format, parseISO, isValid } from 'date-fns';
|
||||
import { ChevronDownIcon } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
function toDate(iso) {
|
||||
if (!iso) return undefined;
|
||||
const d = parseISO(iso);
|
||||
return isValid(d) ? d : undefined;
|
||||
}
|
||||
|
||||
function toTimeString(iso) {
|
||||
if (!iso) return '00:00';
|
||||
const d = parseISO(iso);
|
||||
if (!isValid(d)) return '00:00';
|
||||
return format(d, 'HH:mm');
|
||||
}
|
||||
|
||||
function buildISO(date, timeStr) {
|
||||
if (!date) return null;
|
||||
const [h = '00', m = '00'] = (timeStr ?? '00:00').split(':');
|
||||
const d = new Date(date);
|
||||
d.setHours(Number(h), Number(m), 0, 0);
|
||||
return d.toISOString();
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
export default function DeadlinePicker({ value, onChange, disabled = false }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const selectedDate = toDate(value);
|
||||
const timeStr = toTimeString(value);
|
||||
|
||||
const handleDateSelect = (date) => {
|
||||
onChange(buildISO(date, timeStr));
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const handleTimeChange = (e) => {
|
||||
onChange(buildISO(selectedDate ?? new Date(), e.target.value));
|
||||
};
|
||||
|
||||
const handleClear = () => onChange(null);
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap items-end gap-3">
|
||||
|
||||
{/* ── Date picker ──────────────────────────────────────────────── */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">Date</Label>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
disabled={disabled}
|
||||
className="w-36 justify-between font-normal text-sm"
|
||||
>
|
||||
{selectedDate ? format(selectedDate, 'MMM d, yyyy') : 'Select date'}
|
||||
<ChevronDownIcon className="h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto overflow-hidden p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={selectedDate}
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={selectedDate}
|
||||
onSelect={handleDateSelect}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
{/* ── Time input ───────────────────────────────────────────────── */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs text-muted-foreground">Time</Label>
|
||||
<Input
|
||||
type="time"
|
||||
value={timeStr}
|
||||
onChange={handleTimeChange}
|
||||
disabled={disabled || !selectedDate}
|
||||
step="60"
|
||||
className="w-28 appearance-none bg-background
|
||||
[&::-webkit-calendar-picker-indicator]:hidden
|
||||
[&::-webkit-calendar-picker-indicator]:appearance-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* ── Clear ────────────────────────────────────────────────────── */}
|
||||
{value && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
disabled={disabled}
|
||||
onClick={handleClear}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user