- Add drag-to-resize sidebar with localStorage persistence - Rewrite issue detail page with Tiptap rich text editor, due date picker, acceptance criteria - Redesign create-issue modal with pill-based property toolbar and expand/collapse - Consolidate @multica/sdk and @multica/types into apps/web/shared/ - Simplify auth: remove verification codes, PATs, email service (dev-only login) - Add 401 unauthorized handler to redirect expired sessions to login - Fix due date format to send full RFC3339 timestamps - Increase description editor debounce to 1500ms - Remove arbitrary Tailwind values in create-issue modal - Renumber migrations (inbox_actor 012→009), remove unused migrations - UI polish across agents, settings, inbox, knowledge-base pages Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { CalendarDays } from "lucide-react";
|
|
import type { UpdateIssueRequest } from "@/shared/types";
|
|
import { Calendar } from "@/components/ui/calendar";
|
|
import {
|
|
Popover,
|
|
PopoverTrigger,
|
|
PopoverContent,
|
|
} from "@/components/ui/popover";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export function DueDatePicker({
|
|
dueDate,
|
|
onUpdate,
|
|
}: {
|
|
dueDate: string | null;
|
|
onUpdate: (updates: Partial<UpdateIssueRequest>) => void;
|
|
}) {
|
|
const [open, setOpen] = useState(false);
|
|
const date = dueDate ? new Date(dueDate) : undefined;
|
|
const isOverdue = date ? date < new Date() : false;
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger className="flex items-center gap-1.5 cursor-pointer rounded px-1 -mx-1 hover:bg-accent/30 transition-colors">
|
|
<CalendarDays className="h-3.5 w-3.5 text-muted-foreground" />
|
|
{date ? (
|
|
<span className={isOverdue ? "text-destructive" : ""}>
|
|
{date.toLocaleDateString("en-US", { month: "short", day: "numeric" })}
|
|
</span>
|
|
) : (
|
|
<span className="text-muted-foreground">Due date</span>
|
|
)}
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-auto p-0" align="start">
|
|
<Calendar
|
|
mode="single"
|
|
selected={date}
|
|
onSelect={(d: Date | undefined) => {
|
|
onUpdate({ due_date: d ? d.toISOString() : null });
|
|
setOpen(false);
|
|
}}
|
|
/>
|
|
{date && (
|
|
<div className="border-t px-3 py-2">
|
|
<Button
|
|
variant="ghost"
|
|
size="xs"
|
|
onClick={() => {
|
|
onUpdate({ due_date: null });
|
|
setOpen(false);
|
|
}}
|
|
className="text-muted-foreground hover:text-foreground"
|
|
>
|
|
Clear date
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
}
|