From dddf51affe23157a134218f0e416180d58d3ca75 Mon Sep 17 00:00:00 2001 From: Apple Date: Mon, 1 Dec 2025 10:09:28 -0800 Subject: [PATCH] feat(microdao-rooms): Add MicroDAO rooms creation/deletion and agent chat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend: - POST /city/microdao/{slug}/rooms - create new room for MicroDAO - DELETE /city/microdao/{slug}/rooms/{room_id} - soft-delete room - POST /city/agents/{agent_id}/ensure-room - create personal agent room Frontend: - MicrodaoRoomsSection: Added create room modal with name, description, type - MicrodaoRoomsSection: Added delete room functionality for managers - Agent page: Added 'Поговорити' button to open chat in City Room Models: - Added CreateMicrodaoRoomRequest model Task: TASK_PHASE_MICRODAO_ROOMS_AND_PUBLIC_CHAT_v3 --- apps/web/src/app/agents/[agentId]/page.tsx | 20 ++ apps/web/src/app/microdao/[slug]/page.tsx | 3 + .../microdao/MicrodaoRoomsSection.tsx | 173 +++++++++++++++++- ...PHASE_MICRODAO_ROOMS_AND_PUBLIC_CHAT_v3.md | 46 +++++ services/city-service/models_city.py | 9 + services/city-service/routes_city.py | 173 +++++++++++++++++- 6 files changed, 416 insertions(+), 8 deletions(-) create mode 100644 docs/tasks/TASK_PHASE_MICRODAO_ROOMS_AND_PUBLIC_CHAT_v3.md diff --git a/apps/web/src/app/agents/[agentId]/page.tsx b/apps/web/src/app/agents/[agentId]/page.tsx index 4fbbc95d..400dd9a4 100644 --- a/apps/web/src/app/agents/[agentId]/page.tsx +++ b/apps/web/src/app/agents/[agentId]/page.tsx @@ -268,6 +268,26 @@ export default function AgentConsolePage() { {/* Status & Actions */}
+ {/* Chat Button */} + +
{/* MicroDAO Agents Section - using new API */} diff --git a/apps/web/src/components/microdao/MicrodaoRoomsSection.tsx b/apps/web/src/components/microdao/MicrodaoRoomsSection.tsx index b4d52fc9..beed40ae 100644 --- a/apps/web/src/components/microdao/MicrodaoRoomsSection.tsx +++ b/apps/web/src/components/microdao/MicrodaoRoomsSection.tsx @@ -1,7 +1,7 @@ "use client"; import Link from "next/link"; -import { MessageCircle, Home, Users, FlaskConical, Shield, Gavel, Hash, Users2, Bot, PlusCircle, Crown } from "lucide-react"; +import { MessageCircle, Home, Users, FlaskConical, Shield, Gavel, Hash, Users2, Bot, PlusCircle, Crown, Plus, Trash2, X, Loader2 } from "lucide-react"; import { CityRoomSummary } from "@/lib/types/microdao"; import { CityChatWidget } from "@/components/city/CityChatWidget"; import { Button } from "@/components/ui/button"; @@ -9,10 +9,13 @@ import { useState } from "react"; interface MicrodaoRoomsSectionProps { rooms: CityRoomSummary[]; + microdaoSlug?: string; primaryRoomSlug?: string | null; showAllChats?: boolean; canManage?: boolean; onEnsureOrchestratorRoom?: () => Promise; + onRoomCreated?: () => void; + onRoomDeleted?: () => void; } const ROLE_META: Record = { @@ -107,12 +110,22 @@ const ROLE_META: Record(null); const handleCreateTeam = async () => { if (!onEnsureOrchestratorRoom) return; @@ -126,6 +139,53 @@ export function MicrodaoRoomsSection({ } }; + const handleCreateRoom = async () => { + if (!microdaoSlug || !newRoomName.trim()) return; + setIsCreating(true); + try { + const res = await fetch(`/api/city/microdao/${microdaoSlug}/rooms`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + name: newRoomName.trim(), + description: newRoomDescription.trim() || null, + room_role: newRoomRole, + is_public: newRoomIsPublic, + }), + }); + if (!res.ok) throw new Error("Failed to create room"); + setShowCreateModal(false); + setNewRoomName(""); + setNewRoomDescription(""); + setNewRoomRole("general"); + setNewRoomIsPublic(true); + onRoomCreated?.(); + } catch (e) { + console.error("Failed to create room", e); + alert("Не вдалося створити кімнату"); + } finally { + setIsCreating(false); + } + }; + + const handleDeleteRoom = async (roomId: string, roomName: string) => { + if (!microdaoSlug) return; + if (!confirm(`Видалити кімнату "${roomName}"?`)) return; + setDeletingRoomId(roomId); + try { + const res = await fetch(`/api/city/microdao/${microdaoSlug}/rooms/${roomId}`, { + method: "DELETE", + }); + if (!res.ok) throw new Error("Failed to delete room"); + onRoomDeleted?.(); + } catch (e) { + console.error("Failed to delete room", e); + alert("Не вдалося видалити кімнату"); + } finally { + setDeletingRoomId(null); + } + }; + if (!rooms || rooms.length === 0) { return (
@@ -213,14 +273,113 @@ export function MicrodaoRoomsSection({
)} + {/* Create Room Modal */} + {showCreateModal && ( +
+
+
+

Нова кімната

+ +
+ +
+
+ + setNewRoomName(e.target.value)} + className="w-full px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:border-cyan-500" + placeholder="Назва кімнати" + /> +
+ +
+ +