'use client'; import { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { toast } from 'sonner'; interface ProjectCreationModalProps { open: boolean; onOpenChange: (open: boolean) => void; workspace: string; initialWorkspacePath?: string; } export function ProjectCreationModal({ open, onOpenChange, workspace }: ProjectCreationModalProps) { const router = useRouter(); const [productName, setProductName] = useState(''); const [loading, setLoading] = useState(false); const inputRef = useRef(null); useEffect(() => { if (open) { setProductName(''); setLoading(false); setTimeout(() => inputRef.current?.focus(), 80); } }, [open]); // Close on Escape useEffect(() => { if (!open) return; const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onOpenChange(false); }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, [open, onOpenChange]); const handleCreate = async () => { const name = productName.trim(); if (!name) return; setLoading(true); try { const res = await fetch('/api/projects/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ projectName: name, projectType: 'scratch', slug: name.toLowerCase().replace(/[^a-z0-9]+/g, '-'), product: { name }, }), }); if (!res.ok) { const err = await res.json(); toast.error(err.error || 'Failed to create project'); return; } const data = await res.json(); onOpenChange(false); router.push(`/${workspace}/project/${data.projectId}/overview`); } catch { toast.error('Something went wrong'); } finally { setLoading(false); } }; if (!open) return null; return ( <> {/* Backdrop */}
onOpenChange(false)} style={{ position: 'fixed', inset: 0, zIndex: 50, background: 'rgba(26,26,26,0.35)', animation: 'fadeIn 0.15s ease', }} /> {/* Modal */}
e.stopPropagation()} > {/* Header */}

New project

Give your project a name to get started.

{/* Name input */}
setProductName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && productName.trim() && !loading) handleCreate(); }} placeholder="e.g. Foxglove, Meridian, OpsAI…" style={{ width: '100%', padding: '11px 14px', borderRadius: 8, border: '1px solid #e0dcd4', background: '#faf8f5', fontSize: '0.9rem', fontFamily: 'Outfit, sans-serif', color: '#1a1a1a', outline: 'none', transition: 'border-color 0.12s', boxSizing: 'border-box', }} onFocus={e => (e.currentTarget.style.borderColor = '#1a1a1a')} onBlur={e => (e.currentTarget.style.borderColor = '#e0dcd4')} />
{/* Create button */}
); }