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:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user