feat(ui): make project status clickable in properties pane

Add a ProjectStatusPicker component that renders the status badge as a
clickable button opening a popover with all project statuses. Falls back
to the read-only StatusBadge when no onUpdate handler is provided.
Works in both desktop side panel and mobile sheet layout.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-05 19:00:23 -06:00
parent 1bbb98aaa9
commit f41373dc46

View File

@@ -3,11 +3,12 @@ import { Link } from "@/lib/router";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { Project } from "@paperclipai/shared";
import { StatusBadge } from "./StatusBadge";
import { formatDate } from "../lib/utils";
import { cn, formatDate } from "../lib/utils";
import { goalsApi } from "../api/goals";
import { projectsApi } from "../api/projects";
import { useCompany } from "../context/CompanyContext";
import { queryKeys } from "../lib/queryKeys";
import { statusBadge, statusBadgeDefault } from "../lib/status-colors";
import { Separator } from "@/components/ui/separator";
import { Button } from "@/components/ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
@@ -15,6 +16,14 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
import { ExternalLink, Github, Plus, Trash2, X } from "lucide-react";
import { ChoosePathButton } from "./PathInstructionsModal";
const PROJECT_STATUSES = [
{ value: "backlog", label: "Backlog" },
{ value: "planned", label: "Planned" },
{ value: "in_progress", label: "In Progress" },
{ value: "completed", label: "Completed" },
{ value: "cancelled", label: "Cancelled" },
];
interface ProjectPropertiesProps {
project: Project;
onUpdate?: (data: Record<string, unknown>) => void;
@@ -31,6 +40,42 @@ function PropertyRow({ label, children }: { label: string; children: React.React
);
}
function ProjectStatusPicker({ status, onChange }: { status: string; onChange: (status: string) => void }) {
const [open, setOpen] = useState(false);
const colorClass = statusBadge[status] ?? statusBadgeDefault;
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<button
className={cn(
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium whitespace-nowrap shrink-0 cursor-pointer hover:opacity-80 transition-opacity",
colorClass,
)}
>
{status.replace("_", " ")}
</button>
</PopoverTrigger>
<PopoverContent className="w-40 p-1" align="start">
{PROJECT_STATUSES.map((s) => (
<Button
key={s.value}
variant="ghost"
size="sm"
className={cn("w-full justify-start gap-2 text-xs", s.value === status && "bg-accent")}
onClick={() => {
onChange(s.value);
setOpen(false);
}}
>
{s.label}
</Button>
))}
</PopoverContent>
</Popover>
);
}
export function ProjectProperties({ project, onUpdate }: ProjectPropertiesProps) {
const { selectedCompanyId } = useCompany();
const queryClient = useQueryClient();
@@ -212,7 +257,14 @@ export function ProjectProperties({ project, onUpdate }: ProjectPropertiesProps)
<div className="space-y-4">
<div className="space-y-1">
<PropertyRow label="Status">
<StatusBadge status={project.status} />
{onUpdate ? (
<ProjectStatusPicker
status={project.status}
onChange={(status) => onUpdate({ status })}
/>
) : (
<StatusBadge status={project.status} />
)}
</PropertyRow>
{project.leadAgentId && (
<PropertyRow label="Lead">