frontend changes before tech stack
This commit is contained in:
parent
7c711bc2f8
commit
797f2e8657
@ -119,7 +119,7 @@ export function AICustomFeatureCreator({
|
|||||||
const hasAnyAnalysis = !!aiAnalysis || requirements.some(r => (r.rules || []).length > 0)
|
const hasAnyAnalysis = !!aiAnalysis || requirements.some(r => (r.rules || []).length > 0)
|
||||||
|
|
||||||
const handleAnalyze = async () => {
|
const handleAnalyze = async () => {
|
||||||
if (hasAnyAnalysis) return
|
// Allow analyze even if some analysis exists; we'll only analyze missing items
|
||||||
if (!featureDescription.trim() && requirements.every(r => !r.text.trim())) return
|
if (!featureDescription.trim() && requirements.every(r => !r.text.trim())) return
|
||||||
setIsAnalyzing(true)
|
setIsAnalyzing(true)
|
||||||
setAnalysisError(null)
|
setAnalysisError(null)
|
||||||
@ -146,13 +146,17 @@ export function AICustomFeatureCreator({
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Generate logic rules per requirement in parallel and attach to each requirement
|
// Generate logic rules per requirement in parallel; analyze only those missing rules
|
||||||
const perRequirementRules = await Promise.all(
|
const perRequirementRules = await Promise.all(
|
||||||
requirements.map(async (r) => {
|
requirements.map(async (r) => {
|
||||||
|
// Preserve existing rules if already analyzed
|
||||||
|
if (Array.isArray(r.rules) && r.rules.length > 0) {
|
||||||
|
return r.rules
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const res = await analyzeFeatureWithAI(
|
const res = await analyzeFeatureWithAI(
|
||||||
featureName,
|
r.text || featureName,
|
||||||
featureDescription,
|
r.text || featureDescription,
|
||||||
r.text ? [r.text] : [],
|
r.text ? [r.text] : [],
|
||||||
projectType
|
projectType
|
||||||
)
|
)
|
||||||
@ -172,15 +176,14 @@ export function AICustomFeatureCreator({
|
|||||||
|
|
||||||
const handleAnalyzeRequirement = async (idx: number) => {
|
const handleAnalyzeRequirement = async (idx: number) => {
|
||||||
const req = requirements[idx]
|
const req = requirements[idx]
|
||||||
if (hasAnyAnalysis) return
|
|
||||||
if (!req?.text?.trim()) return
|
if (!req?.text?.trim()) return
|
||||||
if ((req.rules || []).length > 0) return
|
if ((req.rules || []).length > 0) return
|
||||||
setAnalyzingIdx(idx)
|
setAnalyzingIdx(idx)
|
||||||
setAnalysisError(null)
|
setAnalysisError(null)
|
||||||
try {
|
try {
|
||||||
const res = await analyzeFeatureWithAI(
|
const res = await analyzeFeatureWithAI(
|
||||||
featureName,
|
req.text || featureName,
|
||||||
featureDescription,
|
req.text || featureDescription,
|
||||||
[req.text],
|
[req.text],
|
||||||
projectType
|
projectType
|
||||||
)
|
)
|
||||||
@ -269,10 +272,10 @@ export function AICustomFeatureCreator({
|
|||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => handleAnalyzeRequirement(idx)}
|
onClick={() => handleAnalyzeRequirement(idx)}
|
||||||
disabled={isAnalyzing || analyzingIdx === idx || !r.text.trim() || hasAnyAnalysis || (r.rules || []).length > 0}
|
disabled={isAnalyzing || analyzingIdx === idx || !r.text.trim() || (r.rules || []).length > 0}
|
||||||
className="border-white/20 text-white hover:bg-white/10"
|
className="border-white/20 text-white hover:bg-white/10"
|
||||||
>
|
>
|
||||||
{analyzingIdx === idx ? 'Analyzing…' : (((r.rules || []).length > 0) || hasAnyAnalysis ? 'Analyzed' : 'Analyze With AI')}
|
{analyzingIdx === idx ? 'Analyzing…' : ((r.rules || []).length > 0 ? 'Analyzed' : 'Analyze With AI')}
|
||||||
</Button>
|
</Button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -324,7 +327,18 @@ export function AICustomFeatureCreator({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Removed global Analyze button; use per-requirement Analyze instead */}
|
{/* Analyze all requirements (only those missing rules) and compute overall complexity */}
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleAnalyze}
|
||||||
|
disabled={isAnalyzing || (requirements.every(r => !r.text.trim()))}
|
||||||
|
className="border-white/20 text-white hover:bg-white/10"
|
||||||
|
>
|
||||||
|
{isAnalyzing ? 'Analyzing…' : 'Analyze All with AI'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{analysisError && (
|
{analysisError && (
|
||||||
<Card className="p-3 bg-red-500/10 border-red-500/30 text-red-300">{analysisError}</Card>
|
<Card className="p-3 bg-red-500/10 border-red-500/30 text-red-300">{analysisError}</Card>
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import WireframeCanvas from "@/components/wireframe-canvas"
|
|||||||
import PromptSidePanel from "@/components/prompt-side-panel"
|
import PromptSidePanel from "@/components/prompt-side-panel"
|
||||||
import { DualCanvasEditor } from "@/components/dual-canvas-editor"
|
import { DualCanvasEditor } from "@/components/dual-canvas-editor"
|
||||||
import { getAccessToken } from "@/components/apis/authApiClients"
|
import { getAccessToken } from "@/components/apis/authApiClients"
|
||||||
|
import TechStackSummary from "@/components/tech-stack-summary"
|
||||||
|
|
||||||
interface Template {
|
interface Template {
|
||||||
id: string
|
id: string
|
||||||
@ -1308,14 +1309,11 @@ function BusinessQuestionsStep({
|
|||||||
logicRules: (selected as any[]).flatMap((f: any) => f.logicRules || []),
|
logicRules: (selected as any[]).flatMap((f: any) => f.logicRules || []),
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = await fetch(`${BACKEND_URL}/api/v1/select`, {
|
// TODO: Store business context Q&A responses in backend (temporarily disabled)
|
||||||
method: 'POST',
|
console.log('📝 Business context answers:', businessAnswers)
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify(completeData),
|
// Proceed directly to next step with complete data
|
||||||
})
|
onDone(completeData, null)
|
||||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`)
|
|
||||||
const recommendations = await resp.json()
|
|
||||||
onDone(completeData, recommendations)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Tech stack selection failed', e)
|
console.error('Tech stack selection failed', e)
|
||||||
} finally {
|
} finally {
|
||||||
@ -1375,316 +1373,190 @@ function BusinessQuestionsStep({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tech Stack Summary Step
|
|
||||||
function TechStackSummaryStep({
|
|
||||||
recommendations,
|
|
||||||
completeData,
|
|
||||||
onBack,
|
|
||||||
onGenerate,
|
|
||||||
}: { recommendations: any; completeData: any; onBack: () => void; onGenerate: () => void }) {
|
|
||||||
const functional = recommendations?.functional_requirements || {}
|
|
||||||
const claude = recommendations?.claude_recommendations || {}
|
|
||||||
const tech = claude?.technology_recommendations || {}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="max-w-6xl mx-auto space-y-6">
|
|
||||||
<div className="text-center space-y-2">
|
|
||||||
<h2 className="text-3xl font-bold text-white">Technology Stack Recommendations</h2>
|
|
||||||
<p className="text-white/60">AI-powered recommendations for your project</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{functional?.feature_name && (
|
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6">
|
|
||||||
<h3 className="text-xl font-bold text-white mb-4">Functional Requirements Analysis</h3>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<div>
|
|
||||||
<h4 className="font-semibold text-white/80 mb-2">Core Feature</h4>
|
|
||||||
<div className="bg-orange-500 rounded-lg p-4">
|
|
||||||
<div className="font-medium text-white-200">{functional.feature_name}</div>
|
|
||||||
<div className="text-white-300 text-sm mt-1">{functional.description}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{/* <h4 className="font-semibold text-white/80 mb-2">Complexity Level</h4>
|
|
||||||
<div className="rounded-lg p-4">
|
|
||||||
<span className="inline-block px-3 py-1 rounded-full text-sm font-medium bg-white/10 text-white">
|
|
||||||
{(functional.complexity_level || 'medium').toUpperCase()}
|
|
||||||
</span>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{Array.isArray(functional.technical_requirements) && functional.technical_requirements.length > 0 && (
|
|
||||||
<div className="mt-6">
|
|
||||||
<h4 className="font-semibold text-white/80 mb-3">Technical Requirements</h4>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{functional.technical_requirements.map((req: string, i: number) => (
|
|
||||||
<span key={i} className="bg-emerald-500/10 text-emerald-200 px-3 py-1 rounded-full text-sm">{req}</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{Array.isArray(functional.business_logic_rules) && functional.business_logic_rules.length > 0 && (
|
|
||||||
<div className="mt-6">
|
|
||||||
<h4 className="font-semibold text-white/80 mb-3">Business Logic Rules</h4>
|
|
||||||
<div className="space-y-2">
|
|
||||||
{functional.business_logic_rules.map((rule: string, i: number) => (
|
|
||||||
<div key={i} className="bg-orange-500/10 border-l-4 border-orange-400 p-3 text-orange-200 text-sm">{rule}</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6">
|
|
||||||
<h3 className="text-xl font-bold text-white mb-6">AI Technology Recommendations</h3>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
||||||
{tech?.frontend && (
|
|
||||||
<div className="bg-blue-500/10 rounded-lg p-5">
|
|
||||||
<div className="font-bold text-blue-200 mb-2">Frontend</div>
|
|
||||||
<div className="text-blue-300">Framework: {tech.frontend.framework}</div>
|
|
||||||
{Array.isArray(tech.frontend.libraries) && (
|
|
||||||
<div className="mt-2 text-blue-300 text-sm">Libraries: {tech.frontend.libraries.join(', ')}</div>
|
|
||||||
)}
|
|
||||||
{tech.frontend.reasoning && <div className="mt-2 text-blue-300 text-sm">{tech.frontend.reasoning}</div>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{tech?.backend && (
|
|
||||||
<div className="bg-emerald-500/10 rounded-lg p-5">
|
|
||||||
<div className="font-bold text-emerald-200 mb-2">Backend</div>
|
|
||||||
<div className="text-emerald-300">Language: {tech.backend.language}</div>
|
|
||||||
<div className="text-emerald-300">Framework: {tech.backend.framework}</div>
|
|
||||||
{Array.isArray(tech.backend.libraries) && (
|
|
||||||
<div className="mt-2 text-emerald-300 text-sm">Libraries: {tech.backend.libraries.join(', ')}</div>
|
|
||||||
)}
|
|
||||||
{tech.backend.reasoning && <div className="mt-2 text-emerald-300 text-sm">{tech.backend.reasoning}</div>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{tech?.database && (
|
|
||||||
<div className="bg-purple-500/10 rounded-lg p-5">
|
|
||||||
<div className="font-bold text-purple-200 mb-2">Database</div>
|
|
||||||
<div className="text-purple-300">Primary: {tech.database.primary}</div>
|
|
||||||
{Array.isArray(tech.database.secondary) && tech.database.secondary.length > 0 && (
|
|
||||||
<div className="mt-2 text-purple-300 text-sm">Secondary: {tech.database.secondary.join(', ')}</div>
|
|
||||||
)}
|
|
||||||
{tech.database.reasoning && <div className="mt-2 text-purple-300 text-sm">{tech.database.reasoning}</div>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{claude?.implementation_strategy && (
|
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6">
|
|
||||||
<h3 className="text-xl font-bold text-white mb-4">Implementation Strategy</h3>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 text-white/80">
|
|
||||||
<div>
|
|
||||||
<div className="font-semibold mb-2">Architecture Pattern</div>
|
|
||||||
<div className="bg-white/10 rounded-lg p-3">{claude.implementation_strategy.architecture_pattern}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="font-semibold mb-2">Deployment Strategy</div>
|
|
||||||
<div className="bg-white/10 rounded-lg p-3">{claude.implementation_strategy.deployment_strategy}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="text-center py-6">
|
|
||||||
<div className="space-x-4">
|
|
||||||
<Button variant="outline" onClick={onBack} className="border-white/20 text-white hover:bg-white/10 cursor-pointer">Back</Button>
|
|
||||||
<Button onClick={onGenerate} className="bg-gradient-to-r from-orange-500 to-orange-600 text-white px-6 py-2 rounded-lg font-semibold cursor-pointer">Generate Architecture Design →</Button>
|
|
||||||
</div>
|
|
||||||
<div className="text-white/60 text-sm mt-2">AI will design complete architecture</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Mockup Step Component
|
// AI Mockup Step Component
|
||||||
function AIMockupStep({
|
// function AIMockupStep({
|
||||||
template,
|
// template,
|
||||||
selectedFeatures,
|
// selectedFeatures,
|
||||||
onNext,
|
// onNext,
|
||||||
onBack,
|
// onBack,
|
||||||
}: {
|
// }: {
|
||||||
template: Template;
|
// template: Template
|
||||||
selectedFeatures: TemplateFeature[];
|
// selectedFeatures: TemplateFeature[]
|
||||||
onNext: () => void;
|
// onNext: () => void
|
||||||
onBack: () => void
|
// onBack: () => void
|
||||||
}) {
|
// }) {
|
||||||
const [mounted, setMounted] = useState(false)
|
// const [mounted, setMounted] = useState(false)
|
||||||
const [wireframeData, setWireframeData] = useState<any>(null)
|
// const [wireframeData, setWireframeData] = useState<any>(null)
|
||||||
const [isGenerating, setIsGenerating] = useState(false)
|
// const [isGenerating, setIsGenerating] = useState(false)
|
||||||
const [selectedDevice, setSelectedDevice] = useState<'desktop' | 'tablet' | 'mobile'>('desktop')
|
// const [selectedDevice, setSelectedDevice] = useState<'desktop' | 'tablet' | 'mobile'>('desktop')
|
||||||
const [initialPrompt, setInitialPrompt] = useState<string>("")
|
// const [initialPrompt, setInitialPrompt] = useState<string>("")
|
||||||
|
|
||||||
// Load state from localStorage after component mounts
|
// // Load state from localStorage after component mounts
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
setMounted(true)
|
// setMounted(true)
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
// if (typeof window !== 'undefined') {
|
||||||
// Load device type
|
// // Load device type
|
||||||
const savedDevice = localStorage.getItem('wireframe_device_type')
|
// const savedDevice = localStorage.getItem('wireframe_device_type')
|
||||||
if (savedDevice && ['desktop', 'tablet', 'mobile'].includes(savedDevice)) {
|
// if (savedDevice && ['desktop', 'tablet', 'mobile'].includes(savedDevice)) {
|
||||||
setSelectedDevice(savedDevice as 'desktop' | 'tablet' | 'mobile')
|
// setSelectedDevice(savedDevice as 'desktop' | 'tablet' | 'mobile')
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Load wireframe data
|
// // Load wireframe data
|
||||||
const savedWireframeData = localStorage.getItem('wireframe_data')
|
// const savedWireframeData = localStorage.getItem('wireframe_data')
|
||||||
if (savedWireframeData) {
|
// if (savedWireframeData) {
|
||||||
try {
|
// try {
|
||||||
const parsed = JSON.parse(savedWireframeData)
|
// const parsed = JSON.parse(savedWireframeData)
|
||||||
setWireframeData(parsed)
|
// setWireframeData(parsed)
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error('Failed to parse saved wireframe data:', error)
|
// console.error('Failed to parse saved wireframe data:', error)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}, [])
|
// }, [])
|
||||||
|
|
||||||
// Build prompt from selected features and template
|
// // Build prompt from selected features and template
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (!template) return
|
// if (!template) return
|
||||||
const featureNames = (selectedFeatures || []).map(f => f.name).filter(Boolean)
|
// const featureNames = (selectedFeatures || []).map(f => f.name).filter(Boolean)
|
||||||
const base = `${template.title} dashboard`
|
// const base = `${template.title} dashboard`
|
||||||
const parts = featureNames.length > 0 ? ` with ${featureNames.join(', ')}` : ''
|
// const parts = featureNames.length > 0 ? ` with ${featureNames.join(', ')}` : ''
|
||||||
const footer = '. Optimize layout and spacing. Include navigation.'
|
// const footer = '. Optimize layout and spacing. Include navigation.'
|
||||||
const prompt = `${base}${parts}${footer}`
|
// const prompt = `${base}${parts}${footer}`
|
||||||
setInitialPrompt(prompt)
|
// setInitialPrompt(prompt)
|
||||||
}, [template, JSON.stringify(selectedFeatures)])
|
// }, [template, JSON.stringify(selectedFeatures)])
|
||||||
|
|
||||||
const handleWireframeGenerated = (data: any) => {
|
// const handleWireframeGenerated = (data: any) => {
|
||||||
setWireframeData(data)
|
// setWireframeData(data)
|
||||||
setIsGenerating(false)
|
// setIsGenerating(false)
|
||||||
}
|
// }
|
||||||
|
|
||||||
const handleWireframeGenerationStart = () => {
|
// const handleWireframeGenerationStart = () => {
|
||||||
setIsGenerating(true)
|
// setIsGenerating(true)
|
||||||
}
|
// }
|
||||||
|
|
||||||
const handleDeviceChange = (device: 'desktop' | 'tablet' | 'mobile') => {
|
// const handleDeviceChange = (device: 'desktop' | 'tablet' | 'mobile') => {
|
||||||
console.log('DEBUG: AIMockupStep handleDeviceChange called with:', device)
|
// console.log('DEBUG: AIMockupStep handleDeviceChange called with:', device)
|
||||||
console.log('DEBUG: Previous selectedDevice state:', selectedDevice)
|
// console.log('DEBUG: Previous selectedDevice state:', selectedDevice)
|
||||||
|
|
||||||
setSelectedDevice(device)
|
// setSelectedDevice(device)
|
||||||
|
|
||||||
// Save to localStorage (only after mounting)
|
// // Save to localStorage (only after mounting)
|
||||||
if (mounted) {
|
// if (mounted) {
|
||||||
localStorage.setItem('wireframe_device_type', device)
|
// localStorage.setItem('wireframe_device_type', device)
|
||||||
console.log('DEBUG: Saved device type to localStorage:', device)
|
// console.log('DEBUG: Saved device type to localStorage:', device)
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log('DEBUG: New selectedDevice state:', device)
|
// console.log('DEBUG: New selectedDevice state:', device)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Save wireframe data to localStorage when it changes (only after mounting)
|
// // Save wireframe data to localStorage when it changes (only after mounting)
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
if (wireframeData && mounted) {
|
// if (wireframeData && mounted) {
|
||||||
localStorage.setItem('wireframe_data', JSON.stringify(wireframeData))
|
// localStorage.setItem('wireframe_data', JSON.stringify(wireframeData))
|
||||||
}
|
// }
|
||||||
}, [wireframeData, mounted])
|
// }, [wireframeData, mounted])
|
||||||
|
|
||||||
// Debug: Log when selectedDevice prop changes
|
// // Debug: Log when selectedDevice prop changes
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log('DEBUG: AIMockupStep selectedDevice state changed to:', selectedDevice)
|
// console.log('DEBUG: AIMockupStep selectedDevice state changed to:', selectedDevice)
|
||||||
}, [selectedDevice])
|
// }, [selectedDevice])
|
||||||
|
|
||||||
// Debug: Log when selectedDevice prop changes
|
// // Debug: Log when selectedDevice prop changes
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
console.log('DEBUG: WireframeCanvas selectedDevice prop changed to:', selectedDevice)
|
// console.log('DEBUG: WireframeCanvas selectedDevice prop changed to:', selectedDevice)
|
||||||
}, [selectedDevice])
|
// }, [selectedDevice])
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<div className="max-w-7xl mx-auto space-y-6">
|
// <div className="max-w-7xl mx-auto space-y-6">
|
||||||
<div className="text-center space-y-4">
|
// <div className="text-center space-y-4">
|
||||||
<h1 className="text-4xl font-bold text-white">AI Wireframe Mockup</h1>
|
// <h1 className="text-4xl font-bold text-white">AI Wireframe Mockup</h1>
|
||||||
<p className="text-xl text-white/60 max-w-3xl mx-auto">
|
// <p className="text-xl text-white/60 max-w-3xl mx-auto">
|
||||||
Generate and customize wireframes for {template.title} using AI-powered design tools
|
// Generate and customize wireframes for {template.title} using AI-powered design tools
|
||||||
</p>
|
// </p>
|
||||||
<div className="flex items-center justify-center gap-2 text-orange-400">
|
// <div className="flex items-center justify-center gap-2 text-orange-400">
|
||||||
<Palette className="h-5 w-5" />
|
// <Palette className="h-5 w-5" />
|
||||||
<span className="text-sm font-medium">AI-Powered Wireframe Generation</span>
|
// <span className="text-sm font-medium">AI-Powered Wireframe Generation</span>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
{/* Dual Canvas Editor */}
|
// {/* Dual Canvas Editor */}
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl overflow-hidden h-[80vh] min-h-[600px]">
|
// <div className="bg-white/5 border border-white/10 rounded-xl overflow-hidden h-[80vh] min-h-[600px]">
|
||||||
<DualCanvasEditor
|
// <DualCanvasEditor
|
||||||
className="h-full w-full"
|
// className="h-full w-full"
|
||||||
onWireframeGenerated={handleWireframeGenerated}
|
// onWireframeGenerated={handleWireframeGenerated}
|
||||||
onGenerationStart={handleWireframeGenerationStart}
|
// onGenerationStart={handleWireframeGenerationStart}
|
||||||
selectedDevice={selectedDevice}
|
// selectedDevice={selectedDevice}
|
||||||
onDeviceChange={handleDeviceChange}
|
// onDeviceChange={handleDeviceChange}
|
||||||
initialPrompt={initialPrompt}
|
// initialPrompt={initialPrompt}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
{/* Wireframe Status and Controls */}
|
// {/* Wireframe Status and Controls */}
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6">
|
// <div className="bg-white/5 border border-white/10 rounded-xl p-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
// <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
<div className="text-center">
|
// <div className="text-center">
|
||||||
<div className="text-2xl font-bold text-white mb-2">
|
// <div className="text-2xl font-bold text-white mb-2">
|
||||||
{wireframeData ? '✅' : '⏳'}
|
// {wireframeData ? '✅' : '⏳'}
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/80 font-medium">
|
// <div className="text-white/80 font-medium">
|
||||||
{wireframeData ? 'Wireframe Generated' : 'Ready to Generate'}
|
// {wireframeData ? 'Wireframe Generated' : 'Ready to Generate'}
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/60 text-sm">
|
// <div className="text-white/60 text-sm">
|
||||||
{wireframeData ? 'Click Continue to proceed' : 'Use the AI panel to create wireframes'}
|
// {wireframeData ? 'Click Continue to proceed' : 'Use the AI panel to create wireframes'}
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
<div className="text-center">
|
// <div className="text-center">
|
||||||
<div className="text-2xl font-bold text-white mb-2">
|
// <div className="text-2xl font-bold text-white mb-2">
|
||||||
{selectedFeatures.length}
|
// {selectedFeatures.length}
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/80 font-medium">Features Selected</div>
|
// <div className="text-white/80 font-medium">Features Selected</div>
|
||||||
<div className="text-white/60 text-sm">
|
// <div className="text-white/60 text-sm">
|
||||||
{template.title} template
|
// {template.title} template
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
<div className="text-center">
|
// <div className="text-center">
|
||||||
<div className="text-2xl font-bold text-white mb-2">
|
// <div className="text-2xl font-bold text-white mb-2">
|
||||||
{isGenerating ? '🔄' : '🎨'}
|
// {isGenerating ? '🔄' : '🎨'}
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/80 font-medium">
|
// <div className="text-white/80 font-medium">
|
||||||
{isGenerating ? 'Generating...' : 'AI Ready'}
|
// {isGenerating ? 'Generating...' : 'AI Ready'}
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/60 text-sm">
|
// <div className="text-white/60 text-sm">
|
||||||
{isGenerating ? 'Creating wireframe layout' : 'Claude AI powered'}
|
// {isGenerating ? 'Creating wireframe layout' : 'Claude AI powered'}
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
|
|
||||||
{/* Navigation */}
|
// {/* Navigation */}
|
||||||
<div className="text-center py-6">
|
// <div className="text-center py-6">
|
||||||
<div className="space-x-4">
|
// <div className="space-x-4">
|
||||||
<Button variant="outline" onClick={onBack} className="border-white/20 text-white hover:bg-white/10">
|
// <Button variant="outline" onClick={onBack} className="border-white/20 text-white hover:bg-white/10">
|
||||||
← Back to Features
|
// ← Back to Features
|
||||||
</Button>
|
// </Button>
|
||||||
<Button
|
// <Button
|
||||||
onClick={onNext}
|
// onClick={onNext}
|
||||||
disabled={!wireframeData}
|
// disabled={!wireframeData}
|
||||||
className={`bg-orange-500 hover:bg-orange-400 text-black font-semibold py-2 rounded-lg shadow ${!wireframeData ? 'opacity-50 cursor-not-allowed' : ''
|
// className={`bg-orange-500 hover:bg-orange-400 text-black font-semibold py-2 rounded-lg shadow ${!wireframeData ? 'opacity-50 cursor-not-allowed' : ''
|
||||||
}`}
|
// }`}
|
||||||
>
|
// >
|
||||||
Continue to Business Context →
|
// Continue to Business Context →
|
||||||
</Button>
|
// </Button>
|
||||||
</div>
|
// </div>
|
||||||
<div className="text-white/60 text-sm mt-2">
|
// <div className="text-white/60 text-sm mt-2">
|
||||||
{wireframeData
|
// {wireframeData
|
||||||
? 'Wireframe generated successfully! Continue to define business requirements.'
|
// ? 'Wireframe generated successfully! Continue to define business requirements.'
|
||||||
: 'Generate a wireframe first to continue to the next step.'
|
// : 'Generate a wireframe first to continue to the next step.'
|
||||||
}
|
// }
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Main Dashboard Component
|
// Main Dashboard Component
|
||||||
export function MainDashboard() {
|
export function MainDashboard() {
|
||||||
@ -1758,15 +1630,15 @@ export function MainDashboard() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [])
|
}, [mounted])
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{ id: 1, name: "Project Type", description: "Choose template" },
|
{ id: 1, name: "Project Type", description: "Choose template" },
|
||||||
{ id: 2, name: "Features", description: "Select features" },
|
{ id: 2, name: "Features", description: "Select features" },
|
||||||
{ id: 3, name: "AI Mockup", description: "Generate wireframes" },
|
// { id: 3, name: "AI Mockup", description: "Generate wireframes" },
|
||||||
{ id: 4, name: "Business Context", description: "Define requirements" },
|
{ id: 3, name: "Business Context", description: "Define requirements" },
|
||||||
{ id: 5, name: "Generate", description: "Create project" },
|
{ id: 4, name: "Generate", description: "Create project" },
|
||||||
{ id: 6, name: "Architecture", description: "Review & deploy" },
|
{ id: 5, name: "Architecture", description: "Review & deploy" },
|
||||||
]
|
]
|
||||||
|
|
||||||
// Save state to localStorage when it changes (only after mounting)
|
// Save state to localStorage when it changes (only after mounting)
|
||||||
@ -1836,37 +1708,37 @@ export function MainDashboard() {
|
|||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
case 3:
|
case 3:
|
||||||
return selectedTemplate ? (
|
|
||||||
<AIMockupStep
|
|
||||||
template={selectedTemplate}
|
|
||||||
selectedFeatures={selectedFeatures}
|
|
||||||
onNext={() => setCurrentStep(4)}
|
|
||||||
onBack={() => setCurrentStep(2)}
|
|
||||||
/>
|
|
||||||
) : null
|
|
||||||
case 4:
|
|
||||||
return selectedTemplate ? (
|
return selectedTemplate ? (
|
||||||
<BusinessQuestionsStep
|
<BusinessQuestionsStep
|
||||||
template={selectedTemplate}
|
template={selectedTemplate}
|
||||||
selected={selectedFeatures}
|
selected={selectedFeatures}
|
||||||
onBack={() => setCurrentStep(3)}
|
onBack={() => setCurrentStep(2)}
|
||||||
onDone={(data, recs) => { setFinalProjectData(data); setTechStackRecommendations(recs); setCurrentStep(5) }}
|
onDone={(data, recs) => { setFinalProjectData(data); setTechStackRecommendations(recs); setCurrentStep(4) }}
|
||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
case 5:
|
case 4:
|
||||||
|
console.log('🔍 MainDashboard - techStackRecommendations:', techStackRecommendations)
|
||||||
|
console.log('🔍 MainDashboard - finalProjectData:', finalProjectData)
|
||||||
return (
|
return (
|
||||||
<TechStackSummaryStep
|
<TechStackSummary
|
||||||
recommendations={techStackRecommendations}
|
recommendations={techStackRecommendations}
|
||||||
completeData={finalProjectData}
|
completeData={finalProjectData}
|
||||||
onBack={() => setCurrentStep(4)}
|
onBack={() => setCurrentStep(3)}
|
||||||
onGenerate={() => setCurrentStep(6)}
|
onGenerate={(userTechStack) => {
|
||||||
|
// Store user's tech stack if provided
|
||||||
|
if (userTechStack) {
|
||||||
|
console.log('Storing user tech stack:', userTechStack)
|
||||||
|
// You can store this in state or pass it to the next step
|
||||||
|
}
|
||||||
|
setCurrentStep(5)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
case 6:
|
case 5:
|
||||||
return (
|
return (
|
||||||
<ArchitectureDesignerStep
|
<ArchitectureDesignerStep
|
||||||
recommendations={techStackRecommendations}
|
recommendations={techStackRecommendations}
|
||||||
onBack={() => setCurrentStep(5)}
|
onBack={() => setCurrentStep(4)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
|
|||||||
1005
src/components/tech-stack-summary.tsx
Normal file
1005
src/components/tech-stack-summary.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
//
|
//
|
||||||
export const BACKEND_URL = 'https://backend.codenuk.com';
|
// export const BACKEND_URL = 'https://backend.codenuk.com';
|
||||||
|
|
||||||
// export const BACKEND_URL = 'http://192.168.1.17:8000';
|
export const BACKEND_URL = 'http://192.168.1.13:8000';
|
||||||
|
|
||||||
export const SOCKET_URL = BACKEND_URL;
|
export const SOCKET_URL = BACKEND_URL;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user