Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
452 changes: 447 additions & 5 deletions backend/poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ readme = "README.md"
[tool.poetry.dependencies]
python = "^3.10"
pre-commit = "^4.2.0"
uvicorn = {extras = ["standard"], version = "^0.34.2"}


[build-system]
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/app/rooms/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";
import Agents from "@/components/room/agents";
import Chat from "@/components/room/chat";
import DebateHeader from "@/components/room/debate-header";
import Desicion from "@/components/room/desicion";
import UserProfile from "@/components/room/user-profile";
import { rooms } from "@/components/sections/rooms";
import { notFound } from "next/navigation";

export type Props = {
params: {
id: string;
};
};

export async function getRoomById(id: string) {
console.log("Buscando sala: ", id);
return rooms.find((room) => room.id === parseInt(id));
}

export default async function roomById({ params }: Props) {
const roomId = await getRoomById(params.id);

if (!roomId) return notFound();

return (
<div className="w-full min-h-screen bg-blue-900/60 p-4 text-white">
<div className="grid grid-cols-5 grid-rows-5 gap-2">
<DebateHeader params={{ id: params.id }} />
<UserProfile name="Jhon Doe" profession="Trader" />
<Chat user1="Jhon Doe" user2="user2" />
<Agents />
<Desicion />
</div>
</div>
);
}
113 changes: 113 additions & 0 deletions frontend/src/components/create-room.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"use client"

import { useState } from "react";
import { Button } from "./ui/button";
import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
import { DollarSign, MessageSquare, TrendingDown, TrendingUp } from "lucide-react";
import { Dialog, DialogContent, DialogOverlay, DialogPortal, DialogTrigger } from "./ui/dialog";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuPortal } from "./ui/dropdown-menu";

interface createRoomProps {
isOpen: boolean;
onClose: (isOpen: boolean) => void;
}

const networks = ["Ethereum", "Solana", "Polygon", "Bitcoin"];
const typeRoom = ["All", "Buy / Hold / Sell", "Long / Short", "Just Chat"];

function CreateRoom({
isOpen,
onClose,
}: createRoomProps) {
const [ nameRoom, setNameRoom ] = useState('');
const [ roomType, setRoomType ] = useState('');
const [ network, setNetwork ] = useState('');
const [ numberAgents, setNumberAgents ] = useState('');

return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogPortal>
<DialogOverlay className="bg-[#2c582c]/50 fixed inset-0" />
<DialogContent className="bg-[#3ccc3c]/50 fixed top-[50%] left-[50%] w-full max-w-md translate-x-[-50%] translate-y-[-50%] rounded-lg px-4 py-4">
<div className="">
<h1 className="font-extrabold text-2xl">Create room</h1>
<p className="mb-8">Complete the information to create your room</p>
<form className="mb-4 w-full flex flex-col items-center">
<div className="grid grid-cols-2 grid-rows-2 gap-4">
<div className="col-span-2 col-start-1 flex flex-col">
<label className="font-bold">Name</label>
<input type="text" placeholder="Enter room name" className="w-full h-10 border rounded px-2" />
</div>
<div className="col-start-1 row-start-2">
<label className="font-bold">Network</label>
<DropdownMenu>
<DropdownMenuTrigger className="w-full">
<Button className="w-full">
Select your network
</Button>
</DropdownMenuTrigger>
<DropdownMenuPortal>
<DropdownMenuContent className="min-w-[180px] bg-white rounded-md shadow-md p-2 border border-gray-200">
{networks.map((network) => (
<DropdownMenuItem key={network} className="px-3 py-2 text-sm rounded hover:bg-gray-100 cursor-pointer">
{network}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenuPortal>
</DropdownMenu>
</div>
<div className="col-start-2 row-start-2">
<label className="font-bold">Room type</label>
<DropdownMenu>
<DropdownMenuTrigger className="w-full">
<Button variant="default" className="w-full">
Select your type room
</Button>
</DropdownMenuTrigger>
<DropdownMenuPortal>
<DropdownMenuContent className="min-w-[180px] bg-white rounded-md shadow-md p-2 border border-gray-200">
{typeRoom.map((room) => (
<DropdownMenuItem key={room} className="px-3 py-2 text-sm rounded hover:bg-gray-100 cursor-pointer">
{room}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenuPortal>
</DropdownMenu>
</div>
<div className="col-span-2 col-start-1 row-start-3">
<label className="font-bold">Required Number of Agents</label>
<input type="number" placeholder="Enter number of agents" className="w-full h-10 border rounded px-2" />
</div>
<div className="col-span-2 col-start-1 row-start-4">
<label>Choose your icon</label>
<div className="flex flex-row gap-12 justify-center items-center mt-4">
<Button variant="ghost" className="border border-white rounded-lg w-18 h-18">
<TrendingUp className="h-15 w-15" />
</Button>
<Button variant="ghost" className="border border-white rounded-lg w-18 h-18">
<MessageSquare className="h-15 w-15" />
</Button>
<Button variant="ghost" className="border border-white rounded-lg w-18 h-18">
<DollarSign className="h-15 w-15" />
</Button>
<Button variant="ghost" className="border border-white rounded-lg w-18 h-18">
<TrendingDown className="h-15 w-15" />
</Button>
</div>
</div>
</div>
<div className="mt-8 ml-auto flex flex-row gap-4">
<Button variant="outline" className="text-black">Cancel</Button>
<Button variant="secondary" className="bg-[#2c582c] text-white hover:bg-[#3ccc3c] hover:font-bold">Create Room</Button>
</div>
</form>
</div>
</DialogContent>
</DialogPortal>
</Dialog>
)
}

export default CreateRoom;
50 changes: 50 additions & 0 deletions frontend/src/components/room/agentCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { User } from "lucide-react";
import { motion } from "framer-motion";

export default function AgentCard({ agent }: { agent: any }) {
return (
<motion.div
initial={{ opacity: 0, translateY: 20 }}
animate={{ opacity: 1, translateY: 0 }}
transition={{ duration: 0.4, ease: "easeOut" }}
className={`w-full bg-gradient-to-br from-black/30 to-black/10 border ${
agent.trend === "positive" ? "border-green-400/60" : "border-red-400/60"
} rounded-3xl p-4 flex flex-col gap-4 backdrop-blur-md shadow-lg`}
>
<div className="flex items-center gap-4">
<div className="p-1 bg-white/10 rounded-full border border-white/20">
<User className="w-10 h-10 text-white" />
</div>
<div className="flex flex-col leading-tight">
<span className="text-white/90 font-semibold tracking-wide">IA Agent</span>
<span className="text-xs text-white/60">Created by Jhon Doe</span>
</div>
</div>

<p className="text-sm text-white/90 italic border-l-4 border-white/30 pl-3">
{agent.prediction}
</p>

<div className="flex gap-2">
<span className="px-3 py-1 bg-green-900/40 text-green-400 text-xs font-semibold rounded-full border border-green-500/30 shadow-inner">
{agent.tag}
</span>
<span className="px-3 py-1 bg-gray-700/40 text-gray-100 text-xs rounded-full border border-white/10 shadow-inner">
{agent.level}
</span>
</div>

<div className="grid grid-cols-3 gap-2 text-center">
{agent.traits.map((trait: any) => (
<div
key={trait.label}
className="bg-white/10 text-white/90 py-2 rounded-lg flex flex-col items-center border border-white/10 shadow-sm"
>
<span className="text-sm font-bold">{trait.value}%</span>
<span className="text-xs font-light text-white/70">{trait.label}</span>
</div>
))}
</div>
</motion.div>
);
}
35 changes: 35 additions & 0 deletions frontend/src/components/room/agents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import AgentCard from "./agentCard";

export default function Agents() {
return (
<div className="w-full h-[80%] row-span-3 col-start-5 row-start-2 border border-white/50 rounded p-4 overflow-hidden">
<h2 className="font-bold mb-6">Debate Agents</h2>
<section className="flex flex-col gap-2 overflow-y-auto max-h-full">
<AgentCard agent={{
prediction: "Polygon is showing signs of a bullish breakout.",
trend: "positive",
tag: "Analysis",
level: "Level 2",
traits: [
{ label: "Logic", value: 65 },
{ label: "Aggression", value: 45 },
{ label: "Creativity", value: 80 },
],
}}
/>
<AgentCard agent={{
prediction: "Polygon is showing strong bullish momentum.",
trend: "negative",
tag: "macro economics",
level: "Level 8",
traits: [
{ label: "Logic", value: 55 },
{ label: "Aggression", value: 80 },
{ label: "Creativity", value: 40 },
],
}}
/>
</section>
</div>
);
}
91 changes: 91 additions & 0 deletions frontend/src/components/room/chat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"use client";
import { useState } from "react";
import { Button } from "../ui/button";
import { CircleUser, Send, ThumbsDown, ThumbsUp } from "lucide-react";

type Message = {
id: number;
sender: "user1" | "user2";
text: string;
};

type chatProps = {
user1: string;
user2: string;
};

export default function Chat({ user1, user2 }: chatProps) {
const [message, setMessage] = useState<Message[]>([]);
const [input, setInput] = useState("");
const [currentSender, setCurrentSender] = useState<"user1" | "user2">("user1");
const [countLike, setCountLike] = useState(0);
const [countDislike, setCountDislike] = useState(0);

const handleSend = () => {
if (!input.trim()) return;
const newMessage: Message = {
id: message.length + 1,
sender: currentSender,
text: input.trim(),
};
setMessage([...message, newMessage]);
setInput("");
setCurrentSender(currentSender === "user1" ? "user2" : "user1");
};

return (
<div className="col-span-3 row-span-2 col-start-2 row-start-2">
<main className="h-[360px] w-full border border-white rounded overflow-hidden flex flex-col">
<section className="w-full h-full mx-auto rounded p-4 flex flex-col gap-2">
<h2 className="font-bold text-2xl">Debate Chat</h2>
<div className="w-full flex-1 flex flex-col overflow-y-auto p-2 gap-4 border border-white/10 rounded-lg">
{message.map((msg) => (
<div
key={msg.id}
className={`p-3 rounded-2xl w-[75%] max-w-[75%] shadow-md transition-all duration-300 ${msg.sender === "user1" ? "bg-red-600/45 border border-red-700 self-start" : "bg-green-600/45 border border-green-400 self-end"}`}
>
<div className="flex items-center gap-2 mb-1">
<CircleUser className="h-8 w-8 text-white/80" />
<p className="text-md font-semibold text-white">
{msg.sender === "user1" ? user1 : user2}
</p>
</div>
<p className="mx-10 mb-2 text-sm text-white/90 leading-relaxed break-words">
{msg.text}
</p>
<div className="flex items-center gap-4 text-white/70 text-xs mx-4">
<Button
variant="ghost"
size="sm"
onClick={() => setCountLike(countLike + 1)}
className="flex items-center gap-1 hover:text-green-400"
>
<ThumbsUp /> {countLike}
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => setCountDislike(countDislike + 1)}
className="flex items-center gap-1 hover:text-red-400"
>
<ThumbsDown /> {countDislike}
</Button>
</div>
</div>
))}
</div>
<div className="flex gap-2">
<input
className="flex-1 border rounded px-2 py-1"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<Button onClick={handleSend}>
<Send />
</Button>
</div>
</section>
</main>
</div>
);
}
Loading
Loading