Agent toggle switches in ProjectSettings
Agents shown as toggle switches (on/off) instead of dropdown + remove button. Humans listed separately without remove option. Toggle calls addProjectMember/removeProjectMember API.
This commit is contained in:
parent
82c2ff4c53
commit
bd583384d1
@ -75,14 +75,7 @@ export default function ProjectSettings({ project, onUpdated }: Props) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveMember = async (memberId: string) => {
|
||||
try {
|
||||
await removeProjectMember(project.id, memberId);
|
||||
setMembers(members.filter((m) => m.id !== memberId));
|
||||
} catch (e) {
|
||||
console.error("Failed to remove member:", e);
|
||||
}
|
||||
};
|
||||
// handleRemoveMember is now inline in agent toggle
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
@ -180,43 +173,76 @@ export default function ProjectSettings({ project, onUpdated }: Props) {
|
||||
<div className="text-sm text-[var(--muted)]">Загрузка...</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{/* Current Members */}
|
||||
{/* Humans (non-removable except by dropdown) */}
|
||||
<div className="space-y-2">
|
||||
{members.map((member) => (
|
||||
{members.filter(m => m.type !== "agent").map((member) => (
|
||||
<div key={member.slug} className="flex items-center justify-between p-2 bg-[var(--bg)] border border-[var(--border)] rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium ${
|
||||
member.type === "agent" ? "bg-blue-500/20 text-blue-400" : "bg-green-500/20 text-green-400"
|
||||
}`}>
|
||||
{member.type === "agent" ? "A" : "H"}
|
||||
<div className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium bg-green-500/20 text-green-400">
|
||||
H
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-medium">{member.name}</div>
|
||||
<div className="text-xs text-[var(--muted)]">{member.slug} • {member.role}</div>
|
||||
</div>
|
||||
</div>
|
||||
{member.role !== "owner" && (
|
||||
<button
|
||||
onClick={() => handleRemoveMember(member.id)}
|
||||
className="px-2 py-1 text-xs text-red-400 hover:bg-red-500/10 rounded"
|
||||
>
|
||||
Убрать
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Add Member */}
|
||||
{availableMembers.length > 0 && (
|
||||
<div className="flex gap-2">
|
||||
{/* Agents with toggle switches */}
|
||||
<div className="text-xs text-[var(--muted)] mt-4 mb-2">Агенты</div>
|
||||
<div className="space-y-2">
|
||||
{allMembers.filter(m => m.type === "agent").map((agent) => {
|
||||
const isActive = members.some(pm => pm.id === agent.id);
|
||||
return (
|
||||
<div key={agent.id} className="flex items-center justify-between p-2 bg-[var(--bg)] border border-[var(--border)] rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium bg-blue-500/20 text-blue-400">
|
||||
A
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-medium">{agent.name}</div>
|
||||
<div className="text-xs text-[var(--muted)]">{agent.slug}</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
if (isActive) {
|
||||
await removeProjectMember(project.id, agent.id);
|
||||
setMembers(members.filter(m => m.id !== agent.id));
|
||||
} else {
|
||||
await addProjectMember(project.id, agent.id);
|
||||
setMembers([...members, { id: agent.id, name: agent.name, slug: agent.slug, type: agent.type, role: "member" } as ProjectMember]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to toggle agent:", e);
|
||||
}
|
||||
}}
|
||||
className={`relative w-10 h-5 rounded-full transition-colors duration-200 ${
|
||||
isActive ? "bg-[var(--accent)]" : "bg-[var(--border)]"
|
||||
}`}
|
||||
>
|
||||
<span className={`absolute top-0.5 left-0.5 w-4 h-4 rounded-full bg-white transition-transform duration-200 ${
|
||||
isActive ? "translate-x-5" : "translate-x-0"
|
||||
}`} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Add human member */}
|
||||
{availableMembers.filter(m => m.type !== "agent").length > 0 && (
|
||||
<div className="flex gap-2 mt-3">
|
||||
<select
|
||||
value={selectedMember}
|
||||
onChange={(e) => setSelectedMember(e.target.value)}
|
||||
className="flex-1 px-3 py-2 bg-[var(--bg)] border border-[var(--border)] rounded-lg outline-none focus:border-[var(--accent)] text-sm"
|
||||
>
|
||||
<option value="">Добавить участника...</option>
|
||||
{availableMembers.map((member) => (
|
||||
{availableMembers.filter(m => m.type !== "agent").map((member) => (
|
||||
<option key={member.id} value={member.id}>
|
||||
{member.name} ({member.slug}) - {member.type}
|
||||
</option>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user