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) => {
|
// handleRemoveMember is now inline in agent toggle
|
||||||
try {
|
|
||||||
await removeProjectMember(project.id, memberId);
|
|
||||||
setMembers(members.filter((m) => m.id !== memberId));
|
|
||||||
} catch (e) {
|
|
||||||
console.error("Failed to remove member:", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
@ -180,43 +173,76 @@ export default function ProjectSettings({ project, onUpdated }: Props) {
|
|||||||
<div className="text-sm text-[var(--muted)]">Загрузка...</div>
|
<div className="text-sm text-[var(--muted)]">Загрузка...</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{/* Current Members */}
|
{/* Humans (non-removable except by dropdown) */}
|
||||||
<div className="space-y-2">
|
<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 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="flex items-center gap-3">
|
||||||
<div className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium ${
|
<div className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-medium bg-green-500/20 text-green-400">
|
||||||
member.type === "agent" ? "bg-blue-500/20 text-blue-400" : "bg-green-500/20 text-green-400"
|
H
|
||||||
}`}>
|
|
||||||
{member.type === "agent" ? "A" : "H"}
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-sm font-medium">{member.name}</div>
|
<div className="text-sm font-medium">{member.name}</div>
|
||||||
<div className="text-xs text-[var(--muted)]">{member.slug} • {member.role}</div>
|
<div className="text-xs text-[var(--muted)]">{member.slug} • {member.role}</div>
|
||||||
</div>
|
</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>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Add Member */}
|
{/* Agents with toggle switches */}
|
||||||
{availableMembers.length > 0 && (
|
<div className="text-xs text-[var(--muted)] mt-4 mb-2">Агенты</div>
|
||||||
<div className="flex gap-2">
|
<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
|
<select
|
||||||
value={selectedMember}
|
value={selectedMember}
|
||||||
onChange={(e) => setSelectedMember(e.target.value)}
|
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"
|
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>
|
<option value="">Добавить участника...</option>
|
||||||
{availableMembers.map((member) => (
|
{availableMembers.filter(m => m.type !== "agent").map((member) => (
|
||||||
<option key={member.id} value={member.id}>
|
<option key={member.id} value={member.id}>
|
||||||
{member.name} ({member.slug}) - {member.type}
|
{member.name} ({member.slug}) - {member.type}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user