-
-
Notifications
You must be signed in to change notification settings - Fork 145
feat(ui): Collaboration Hub #98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
0124657
f1f63d3
9efa3ec
ad8a1b3
0511c50
f87cc52
559ba8c
876749f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| import React from "react"; | ||
| import { Button } from "../ui/button"; | ||
| import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; | ||
|
|
||
| export interface ActiveCollabCardProps { | ||
| collaborator: { | ||
| name: string; | ||
| avatar: string; | ||
| contentType: string; | ||
| }; | ||
| collabTitle: string; | ||
| status: string; | ||
| startDate: string; | ||
| dueDate: string; | ||
| messages: number; | ||
| deliverables: { completed: number; total: number }; | ||
| lastActivity: string; | ||
| latestUpdate: string; | ||
| } | ||
|
|
||
| const statusColors: Record<string, string> = { | ||
| "In Progress": "bg-blue-100 text-blue-700", | ||
| "Awaiting Response": "bg-yellow-100 text-yellow-700", | ||
| "Completed": "bg-green-100 text-green-700" | ||
| }; | ||
|
|
||
| function getDaysBetween(start: string, end: string) { | ||
| const s = new Date(start); | ||
| const e = new Date(end); | ||
| return Math.ceil((e.getTime() - s.getTime()) / (1000 * 60 * 60 * 24)); | ||
| } | ||
|
|
||
| function getDaysLeft(due: string) { | ||
| const now = new Date(); | ||
| const d = new Date(due); | ||
| return Math.ceil((d.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); | ||
| } | ||
|
|
||
| function getTimelineProgress(start: string, due: string) { | ||
| const total = getDaysBetween(start, due); | ||
| const elapsed = getDaysBetween(start, new Date().toISOString().slice(0, 10)); | ||
| return Math.min(100, Math.max(0, Math.round((elapsed / total) * 100))); | ||
| } | ||
|
|
||
| const ActiveCollabCard: React.FC<ActiveCollabCardProps> = ({ | ||
| collaborator, | ||
| collabTitle, | ||
| status, | ||
| startDate, | ||
| dueDate, | ||
| messages, | ||
| deliverables, | ||
| lastActivity, | ||
| latestUpdate | ||
| }) => { | ||
| const deliverableProgress = Math.round((deliverables.completed / deliverables.total) * 100); | ||
| const timelineProgress = getTimelineProgress(startDate, dueDate); | ||
| const daysLeft = getDaysLeft(dueDate); | ||
| const overdue = daysLeft < 0 && status !== "Completed"; | ||
|
|
||
| return ( | ||
| <div className="bg-white rounded-xl shadow p-5 flex flex-col gap-3 border border-gray-100 w-full max-w-xl mx-auto"> | ||
| <div className="flex items-center gap-4"> | ||
| <Avatar className="h-12 w-12"> | ||
| <AvatarImage src={collaborator.avatar} alt={collaborator.name} /> | ||
| <AvatarFallback className="bg-gray-200">{collaborator.name.slice(0,2).toUpperCase()}</AvatarFallback> | ||
| </Avatar> | ||
| <div className="flex-1"> | ||
| <div className="font-semibold text-lg text-gray-900">{collaborator.name}</div> | ||
| <div className="text-xs text-gray-500">{collaborator.contentType}</div> | ||
| </div> | ||
| <span className={`px-3 py-1 rounded-full text-xs font-semibold ${statusColors[status] || "bg-gray-100 text-gray-700"}`}>{status}</span> | ||
| </div> | ||
| <div className="flex flex-wrap items-center gap-2 text-sm text-gray-700"> | ||
| <span className="font-semibold">Collab:</span> {collabTitle} | ||
| <span className="ml-4 font-semibold">Start:</span> {startDate} | ||
| <span className="ml-4 font-semibold">Due:</span> <span className={overdue ? "text-red-600 font-bold" : ""}>{dueDate}</span> | ||
| <span className="ml-4 font-semibold">{overdue ? `Overdue by ${Math.abs(daysLeft)} days` : daysLeft === 0 ? "Due today" : `${daysLeft} days left`}</span> | ||
| </div> | ||
| {/* Timeline Progress Bar */} | ||
| <div className="w-full flex flex-col gap-1"> | ||
| <div className="flex justify-between text-xs text-gray-500"> | ||
| <span>Timeline</span> | ||
| <span>{timelineProgress}%</span> | ||
| </div> | ||
| <div className="w-full h-2 bg-gray-200 rounded-full overflow-hidden"> | ||
| <div className="h-2 rounded-full bg-blue-400" style={{ width: `${timelineProgress}%` }} /> | ||
| </div> | ||
| </div> | ||
| {/* Deliverables Progress Bar */} | ||
| <div className="w-full flex flex-col gap-1"> | ||
| <div className="flex justify-between text-xs text-gray-500"> | ||
| <span>Deliverables</span> | ||
| <span>{deliverables.completed}/{deliverables.total} ({deliverableProgress}%)</span> | ||
| </div> | ||
| <div className="w-full h-2 bg-gray-200 rounded-full overflow-hidden"> | ||
| <div className="h-2 rounded-full bg-green-400" style={{ width: `${deliverableProgress}%` }} /> | ||
| </div> | ||
| </div> | ||
| <div className="flex flex-wrap items-center gap-4 text-xs text-gray-600"> | ||
| <span>Messages: <span className="font-semibold text-gray-900">{messages}</span></span> | ||
| <span>Last activity: <span className="font-semibold text-gray-900">{lastActivity}</span></span> | ||
| </div> | ||
| <div className="text-xs text-gray-700 italic bg-gray-50 rounded px-3 py-2 border border-gray-100"> | ||
| <span className="font-semibold text-gray-800">Latest update:</span> {latestUpdate} | ||
| </div> | ||
| <div className="flex gap-2 mt-2"> | ||
| <Button className="bg-gray-100 text-gray-900 hover:bg-gray-200 font-semibold rounded-full py-2" variant="secondary">View Details</Button> | ||
| <Button className="bg-blue-100 text-blue-700 hover:bg-blue-200 font-semibold rounded-full py-2">Message</Button> | ||
| {status !== "Completed" && ( | ||
| <Button className="bg-green-100 text-green-700 hover:bg-green-200 font-semibold rounded-full py-2">Mark Complete</Button> | ||
| )} | ||
| </div> | ||
|
Saahi30 marked this conversation as resolved.
|
||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ActiveCollabCard; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import React, { useState } from "react"; | ||
| import { activeCollabsMock } from "./activeCollabsMockData"; | ||
| import ActiveCollabCard from "./ActiveCollabCard"; | ||
|
|
||
| const statusOptions = ["All", "In Progress", "Completed"]; | ||
| const sortOptions = ["Start Date", "Due Date", "Name"]; | ||
|
|
||
| const ActiveCollabsGrid: React.FC = () => { | ||
| const [statusFilter, setStatusFilter] = useState("All"); | ||
| const [sortBy, setSortBy] = useState("Start Date"); | ||
|
|
||
| // Only show In Progress and Completed | ||
| let filtered = activeCollabsMock.filter(c => c.status !== "Awaiting Response"); | ||
| if (statusFilter !== "All") { | ||
| filtered = filtered.filter(c => c.status === statusFilter); | ||
| } | ||
| if (sortBy === "Start Date") { | ||
| filtered = [...filtered].sort((a, b) => a.startDate.localeCompare(b.startDate)); | ||
| } else if (sortBy === "Due Date") { | ||
| filtered = [...filtered].sort((a, b) => a.dueDate.localeCompare(b.dueDate)); | ||
| } else if (sortBy === "Name") { | ||
| filtered = [...filtered].sort((a, b) => a.collaborator.name.localeCompare(b.collaborator.name)); | ||
| } | ||
|
|
||
| return ( | ||
| <div className="w-full max-w-4xl mx-auto"> | ||
| <div className="flex flex-wrap items-center justify-between gap-4 mb-6"> | ||
| <div className="flex gap-2 items-center"> | ||
| <span className="font-semibold text-gray-700">Status:</span> | ||
| <select | ||
| className="border rounded px-2 py-1 text-sm" | ||
| value={statusFilter} | ||
| onChange={e => setStatusFilter(e.target.value)} | ||
| > | ||
| {statusOptions.map(opt => ( | ||
| <option key={opt} value={opt}>{opt}</option> | ||
| ))} | ||
| </select> | ||
| </div> | ||
| <div className="flex gap-2 items-center"> | ||
| <span className="font-semibold text-gray-700">Sort by:</span> | ||
| <select | ||
| className="border rounded px-2 py-1 text-sm" | ||
| value={sortBy} | ||
| onChange={e => setSortBy(e.target.value)} | ||
| > | ||
| {sortOptions.map(opt => ( | ||
| <option key={opt} value={opt}>{opt}</option> | ||
| ))} | ||
| </select> | ||
| </div> | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| </div> | ||
| {filtered.length === 0 ? ( | ||
| <div className="text-center text-gray-400 py-16"> | ||
| <div className="text-2xl mb-2">No active collaborations</div> | ||
| <div className="text-sm">Start a new collaboration to see it here!</div> | ||
| </div> | ||
| ) : ( | ||
| <div className="flex flex-col gap-6"> | ||
| {filtered.map(collab => ( | ||
| <ActiveCollabCard key={collab.id} {...collab} /> | ||
| ))} | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ActiveCollabsGrid; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,113 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| import React, { useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { mockProfileDetails, mockCollabIdeas, mockRequestTexts, mockWhyMatch } from "./mockProfileData"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+2
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add missing useEffect import for keyboard accessibility. The component needs -import React, { useState } from "react";
+import React, { useState, useEffect } from "react";Then add escape key handling after line 25: const [selectedText, setSelectedText] = useState(mockRequestTexts[0]);
+
+ useEffect(() => {
+ const handleEscape = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') {
+ onClose();
+ }
+ };
+ if (open) {
+ document.addEventListener('keydown', handleEscape);
+ return () => document.removeEventListener('keydown', handleEscape);
+ }
+ }, [open, onClose]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| import { Button } from "../ui/button"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar"; | ||||||||||||||||||||||||||||||||||||||||||||||
| import { Badge } from "../ui/badge"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| interface WhyMatchReason { | ||||||||||||||||||||||||||||||||||||||||||||||
| point: string; | ||||||||||||||||||||||||||||||||||||||||||||||
| description: string; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| interface ConnectModalProps { | ||||||||||||||||||||||||||||||||||||||||||||||
| open: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||
| onClose: () => void; | ||||||||||||||||||||||||||||||||||||||||||||||
| onSend: (selectedText: string) => void; | ||||||||||||||||||||||||||||||||||||||||||||||
| matchPercentage?: number; | ||||||||||||||||||||||||||||||||||||||||||||||
| whyMatch?: WhyMatchReason[]; | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const defaultMatch = 98; | ||||||||||||||||||||||||||||||||||||||||||||||
| const IDEAS_PER_PAGE = 3; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const ConnectModal: React.FC<ConnectModalProps> = ({ open, onClose, onSend, matchPercentage = defaultMatch, whyMatch = mockWhyMatch }) => { | ||||||||||||||||||||||||||||||||||||||||||||||
| const [ideasPage, setIdeasPage] = useState(0); | ||||||||||||||||||||||||||||||||||||||||||||||
| const [selectedText, setSelectedText] = useState(mockRequestTexts[0]); | ||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add defensive programming for mock data access. The component assumes -const [selectedText, setSelectedText] = useState(mockRequestTexts[0]);
+const [selectedText, setSelectedText] = useState(mockRequestTexts[0] || "");📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| if (!open) return null; | ||||||||||||||||||||||||||||||||||||||||||||||
| const profile = mockProfileDetails; | ||||||||||||||||||||||||||||||||||||||||||||||
| const totalIdeas = mockCollabIdeas.length; | ||||||||||||||||||||||||||||||||||||||||||||||
| const startIdx = (ideasPage * IDEAS_PER_PAGE) % totalIdeas; | ||||||||||||||||||||||||||||||||||||||||||||||
| const ideasToShow = Array.from({ length: IDEAS_PER_PAGE }, (_, i) => mockCollabIdeas[(startIdx + i) % totalIdeas]); | ||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const handleNextIdeas = () => { | ||||||||||||||||||||||||||||||||||||||||||||||
| setIdeasPage((prev) => prev + 1); | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-20"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="bg-white rounded-2xl shadow-xl w-auto min-w-[320px] max-w-full mx-2 p-0 sm:p-0 relative flex flex-col sm:flex-row overflow-hidden"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <button className="absolute top-4 right-4 text-gray-400 hover:text-gray-700 z-10" onClick={onClose} aria-label="Close"> | ||||||||||||||||||||||||||||||||||||||||||||||
| × | ||||||||||||||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||||||||||||||
|
Saahi30 marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||
| {/* Left: Profile Info */} | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-col items-center sm:items-start bg-gray-50 sm:bg-white p-6 sm:p-8 w-full sm:w-auto border-b sm:border-b-0 sm:border-r border-gray-100"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Badge className="bg-yellow-100 text-yellow-700 text-sm font-semibold px-3 py-1 mb-2"> | ||||||||||||||||||||||||||||||||||||||||||||||
| {matchPercentage}% Match | ||||||||||||||||||||||||||||||||||||||||||||||
| </Badge> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Avatar className="h-16 w-16 mb-2"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <AvatarImage src={profile.avatar} alt={profile.name} /> | ||||||||||||||||||||||||||||||||||||||||||||||
| <AvatarFallback className="bg-gray-200">{profile.name.slice(0,2).toUpperCase()}</AvatarFallback> | ||||||||||||||||||||||||||||||||||||||||||||||
| </Avatar> | ||||||||||||||||||||||||||||||||||||||||||||||
| <h2 className="text-xl font-bold text-gray-900 text-center sm:text-left">Connect with {profile.name}</h2> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="text-gray-500 text-sm text-center sm:text-left mb-2">{profile.contentType}</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="mb-3 bg-gray-50 border border-gray-100 rounded-lg p-3 w-full"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="font-semibold text-sm mb-1">Why you match</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <ul className="space-y-3"> | ||||||||||||||||||||||||||||||||||||||||||||||
| {whyMatch.map((reason, idx) => ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <li key={idx}> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="font-semibold text-xs text-gray-800 mb-1">{reason.point}</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="text-xs text-gray-600 pl-2">{reason.description}</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </li> | ||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||
| </ul> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| {/* Right: Ideas and Messages */} | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex-1 flex flex-col p-6 sm:p-8 w-full sm:w-auto"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="mb-4"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="font-semibold text-sm mb-2">AI-Generated Collaboration Ideas</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <ul className="space-y-2"> | ||||||||||||||||||||||||||||||||||||||||||||||
| {ideasToShow.map((idea, idx) => ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <li key={idx} className="bg-gray-50 rounded-lg p-3 border border-gray-100"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="font-semibold text-gray-800">{idea.title}</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="text-xs text-gray-600">{idea.description}</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </li> | ||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||
| </ul> | ||||||||||||||||||||||||||||||||||||||||||||||
| {totalIdeas > IDEAS_PER_PAGE && ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex justify-center mt-3"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Button className="bg-yellow-100 text-yellow-800 hover:bg-yellow-200 font-semibold rounded-full px-6 py-2 text-sm" onClick={handleNextIdeas}> | ||||||||||||||||||||||||||||||||||||||||||||||
| See More Ideas | ||||||||||||||||||||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="mb-4"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="font-semibold text-sm mb-2">Select a message to send</div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-2"> | ||||||||||||||||||||||||||||||||||||||||||||||
| {mockRequestTexts.map((text, idx) => ( | ||||||||||||||||||||||||||||||||||||||||||||||
| <label key={idx} className="flex items-start gap-2 cursor-pointer"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||
| type="radio" | ||||||||||||||||||||||||||||||||||||||||||||||
| name="requestText" | ||||||||||||||||||||||||||||||||||||||||||||||
| value={text} | ||||||||||||||||||||||||||||||||||||||||||||||
| checked={selectedText === text} | ||||||||||||||||||||||||||||||||||||||||||||||
| onChange={() => setSelectedText(text)} | ||||||||||||||||||||||||||||||||||||||||||||||
| className="mt-1 accent-yellow-400" | ||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||
| <span className={`text-sm px-4 py-2 rounded-2xl inline-block ${selectedText === text ? 'bg-yellow-100 text-yellow-900 border border-yellow-300' : 'bg-gray-100 text-gray-700'}`}>{text}</span> | ||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex gap-2 w-full mt-auto justify-center pt-2 pb-2"> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Button className="bg-gray-100 text-gray-900 hover:bg-gray-200 flex-1 font-semibold rounded-full py-2" variant="secondary" onClick={onClose}>Cancel</Button> | ||||||||||||||||||||||||||||||||||||||||||||||
| <Button className="bg-yellow-400 text-white hover:bg-yellow-500 flex-1 font-semibold rounded-full py-2" onClick={() => onSend(selectedText)}>Send Request</Button> | ||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add safety check before sending request. The send button should be disabled when no message is selected to prevent sending empty requests. -<Button className="bg-yellow-400 text-white hover:bg-yellow-500 flex-1 font-semibold rounded-full py-2" onClick={() => onSend(selectedText)}>Send Request</Button>
+<Button
+ className="bg-yellow-400 text-white hover:bg-yellow-500 flex-1 font-semibold rounded-full py-2 disabled:opacity-50 disabled:cursor-not-allowed"
+ onClick={() => onSend(selectedText)}
+ disabled={!selectedText.trim()}
+>
+ Send Request
+</Button>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| export default ConnectModal; | ||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.