190 lines
8.3 KiB
TypeScript
190 lines
8.3 KiB
TypeScript
"use client";
|
||
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Badge } from "@/components/ui/badge";
|
||
import { ExternalLink, Copy, CheckCircle2 } from "lucide-react";
|
||
import { useState } from "react";
|
||
|
||
interface MCPConnectModalProps {
|
||
open: boolean;
|
||
onOpenChange: (open: boolean) => void;
|
||
projectId: string;
|
||
}
|
||
|
||
export function MCPConnectModal({
|
||
open,
|
||
onOpenChange,
|
||
projectId,
|
||
}: MCPConnectModalProps) {
|
||
const [copied, setCopied] = useState(false);
|
||
const mcpUrl = `https://api.vibn.co/mcp/projects/${projectId}`;
|
||
|
||
const copyToClipboard = () => {
|
||
navigator.clipboard.writeText(mcpUrl);
|
||
setCopied(true);
|
||
setTimeout(() => setCopied(false), 2000);
|
||
};
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent className="max-w-2xl">
|
||
<DialogHeader>
|
||
<div className="flex items-center gap-3 mb-2">
|
||
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-gradient-to-br from-green-500/20 to-emerald-500/20">
|
||
<svg
|
||
width="20"
|
||
height="20"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
>
|
||
<path
|
||
d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"
|
||
fill="currentColor"
|
||
className="text-green-600"
|
||
/>
|
||
</svg>
|
||
</div>
|
||
<div>
|
||
<DialogTitle className="text-xl">Connect ChatGPT</DialogTitle>
|
||
<Badge variant="secondary" className="mt-1 text-xs">MCP Protocol</Badge>
|
||
</div>
|
||
</div>
|
||
<DialogDescription>
|
||
Link your ChatGPT to this project for real-time sync and AI-powered updates
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
|
||
<div className="space-y-6 mt-4">
|
||
{/* Step 1 */}
|
||
<div className="space-y-3">
|
||
<div className="flex items-center gap-2">
|
||
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-primary/10 text-sm font-medium">
|
||
1
|
||
</div>
|
||
<h3 className="font-semibold">Copy your MCP Server URL</h3>
|
||
</div>
|
||
<div className="ml-8 space-y-2">
|
||
<div className="flex gap-2">
|
||
<Input
|
||
value={mcpUrl}
|
||
readOnly
|
||
className="font-mono text-sm"
|
||
/>
|
||
<Button
|
||
variant="outline"
|
||
size="icon"
|
||
onClick={copyToClipboard}
|
||
>
|
||
{copied ? (
|
||
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
||
) : (
|
||
<Copy className="h-4 w-4" />
|
||
)}
|
||
</Button>
|
||
</div>
|
||
<p className="text-xs text-muted-foreground">
|
||
This unique URL connects ChatGPT to your project
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Step 2 */}
|
||
<div className="space-y-3">
|
||
<div className="flex items-center gap-2">
|
||
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-primary/10 text-sm font-medium">
|
||
2
|
||
</div>
|
||
<h3 className="font-semibold">Add Connector in ChatGPT</h3>
|
||
</div>
|
||
<div className="ml-8 space-y-2">
|
||
<ol className="text-sm space-y-2 text-muted-foreground list-decimal list-inside">
|
||
<li>Open ChatGPT settings</li>
|
||
<li>Navigate to <strong className="text-foreground">Connectors</strong></li>
|
||
<li>Click <strong className="text-foreground">New Connector</strong></li>
|
||
<li>Paste the MCP Server URL</li>
|
||
<li>Select <strong className="text-foreground">OAuth</strong> authentication</li>
|
||
</ol>
|
||
<Button variant="outline" size="sm" className="mt-3" asChild>
|
||
<a href="https://chatgpt.com/settings" target="_blank" rel="noopener noreferrer">
|
||
Open ChatGPT Settings
|
||
<ExternalLink className="ml-2 h-3 w-3" />
|
||
</a>
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Step 3 */}
|
||
<div className="space-y-3">
|
||
<div className="flex items-center gap-2">
|
||
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-primary/10 text-sm font-medium">
|
||
3
|
||
</div>
|
||
<h3 className="font-semibold">Authorize Access</h3>
|
||
</div>
|
||
<div className="ml-8">
|
||
<p className="text-sm text-muted-foreground">
|
||
ChatGPT will request permission to:
|
||
</p>
|
||
<ul className="mt-2 text-sm space-y-1 text-muted-foreground">
|
||
<li className="flex items-center gap-2">
|
||
<span className="text-green-600">✓</span>
|
||
Read your project vision and progress
|
||
</li>
|
||
<li className="flex items-center gap-2">
|
||
<span className="text-green-600">✓</span>
|
||
Add features and tasks
|
||
</li>
|
||
<li className="flex items-center gap-2">
|
||
<span className="text-green-600">✓</span>
|
||
Update documentation
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Info Box */}
|
||
<div className="rounded-lg bg-blue-500/10 border border-blue-500/20 p-4">
|
||
<div className="flex gap-3">
|
||
<div className="text-blue-600 shrink-0">ℹ️</div>
|
||
<div className="text-sm space-y-1">
|
||
<p className="font-medium text-foreground">What happens after connecting?</p>
|
||
<p className="text-muted-foreground">
|
||
You'll be able to chat with ChatGPT about your project, and it will automatically
|
||
sync updates to your Vib'n workspace. Plan features, discuss architecture, and track
|
||
progress - all seamlessly connected.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Actions */}
|
||
<div className="flex justify-between pt-4 border-t">
|
||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||
Close
|
||
</Button>
|
||
<Button variant="outline" asChild>
|
||
<a
|
||
href="https://platform.openai.com/docs/mcp"
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
>
|
||
View MCP Docs
|
||
<ExternalLink className="ml-2 h-3 w-3" />
|
||
</a>
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
}
|
||
|