"use client"; import { useState } from "react"; import { Lock, UserMinus } from "lucide-react"; import type { Agent, IssueAssigneeType, UpdateIssueRequest } from "@/shared/types"; import { useAuthStore } from "@/features/auth"; import { useWorkspaceStore, useActorName } from "@/features/workspace"; import { ActorAvatar } from "@/components/common/actor-avatar"; import { PropertyPicker, PickerItem, PickerSection, PickerEmpty, } from "./property-picker"; export function canAssignAgent(agent: Agent, userId: string | undefined, memberRole: string | undefined): boolean { if (agent.visibility !== "private") return true; if (agent.owner_id === userId) return true; if (memberRole === "owner" || memberRole === "admin") return true; return false; } export function AssigneePicker({ assigneeType, assigneeId, onUpdate, trigger: customTrigger, triggerRender, open: controlledOpen, onOpenChange: controlledOnOpenChange, align, }: { assigneeType: IssueAssigneeType | null; assigneeId: string | null; onUpdate: (updates: Partial) => void; trigger?: React.ReactNode; triggerRender?: React.ReactElement; open?: boolean; onOpenChange?: (v: boolean) => void; align?: "start" | "center" | "end"; }) { const [internalOpen, setInternalOpen] = useState(false); const open = controlledOpen ?? internalOpen; const setOpen = controlledOnOpenChange ?? setInternalOpen; const [filter, setFilter] = useState(""); const user = useAuthStore((s) => s.user); const members = useWorkspaceStore((s) => s.members); const agents = useWorkspaceStore((s) => s.agents); const { getActorName } = useActorName(); const currentMember = members.find((m) => m.user_id === user?.id); const memberRole = currentMember?.role; const query = filter.toLowerCase(); const filteredMembers = members.filter((m) => m.name.toLowerCase().includes(query), ); const filteredAgents = agents.filter((a) => a.name.toLowerCase().includes(query), ); const isSelected = (type: string, id: string) => assigneeType === type && assigneeId === id; const triggerLabel = assigneeType && assigneeId ? getActorName(assigneeType, assigneeId) : "Unassigned"; return ( { setOpen(v); if (!v) setFilter(""); }} width="w-52" align={align} searchable searchPlaceholder="Assign to..." onSearchChange={setFilter} triggerRender={triggerRender} trigger={ customTrigger ? customTrigger : assigneeType && assigneeId ? ( <> {triggerLabel} ) : ( Unassigned ) } > {/* Unassigned option */} { onUpdate({ assignee_type: null, assignee_id: null }); setOpen(false); }} > Unassigned {/* Members */} {filteredMembers.length > 0 && ( {filteredMembers.map((m) => ( { onUpdate({ assignee_type: "member", assignee_id: m.user_id, }); setOpen(false); }} > {m.name} ))} )} {/* Agents */} {filteredAgents.length > 0 && ( {filteredAgents.map((a) => { const allowed = canAssignAgent(a, user?.id, memberRole); return ( { if (!allowed) return; onUpdate({ assignee_type: "agent", assignee_id: a.id, }); setOpen(false); }} > {a.name} {a.visibility === "private" && ( )} ); })} )} {filteredMembers.length === 0 && filteredAgents.length === 0 && filter && } ); }