codenuk_backend_mine/services/web-dashboard/src/components/project-builder/BusinessQuestionsScreen.js
2025-10-03 10:13:06 +05:30

292 lines
11 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import useProjectStore from '../../store/projectStore';
export default function BusinessQuestionsScreen() {
const [businessQuestions, setBusinessQuestions] = useState([]);
const [businessAnswers, setBusinessAnswers] = useState({});
const [isLoadingQuestions, setIsLoadingQuestions] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(null);
const { selectedFeatures, setCurrentStep, projectName, projectType } = useProjectStore();
// Load business questions when component mounts
useEffect(() => {
loadBusinessQuestions();
}, []);
const loadBusinessQuestions = async () => {
try {
setIsLoadingQuestions(true);
setError(null);
if (selectedFeatures.length === 0) {
setError('No features found to generate business questions');
return;
}
console.log('🚀 Generating comprehensive business questions for integrated system:', selectedFeatures);
// Call the new comprehensive endpoint
// Prefer an environment-provided backend URL for frontend builds (REACT_APP_BACKEND_URL or NEXT_PUBLIC_BACKEND_URL).
const backendBase = (process.env.REACT_APP_BACKEND_URL || process.env.NEXT_PUBLIC_BACKEND_URL || '').replace(/\/$/, '') || '';
const getApiUrl = (endpoint) => {
const clean = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
if (backendBase) return `${backendBase}/${clean}`;
// Fallback to relative path (assumes frontend is served with proxy to backend)
return `/${clean}`;
};
const response = await fetch(getApiUrl('api/v1/generate-comprehensive-business-questions'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
allFeatures: selectedFeatures, // Send ALL features with their logic rules
projectName: projectName,
projectType: projectType,
totalFeatures: selectedFeatures.length
}),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('✅ Comprehensive business questions response:', data);
if (data.success && data.data.businessQuestions) {
setBusinessQuestions(data.data.businessQuestions);
// Initialize answers object
const initialAnswers = {};
data.data.businessQuestions.forEach((question, index) => {
initialAnswers[index] = '';
});
setBusinessAnswers(initialAnswers);
console.log(`🎯 Generated ${data.data.businessQuestions.length} comprehensive questions for integrated system`);
} else {
setError('Failed to generate comprehensive business questions');
}
} catch (error) {
console.error('❌ Error loading comprehensive business questions:', error);
setError(`Failed to load business questions: ${error.message}`);
} finally {
setIsLoadingQuestions(false);
}
};
const handleAnswerChange = (questionIndex, answer) => {
setBusinessAnswers(prev => ({
...prev,
[questionIndex]: answer
}));
};
const handleSubmit = async () => {
try {
setIsSubmitting(true);
// Validate that at least some questions are answered
const answeredQuestions = Object.values(businessAnswers).filter(answer => answer.trim()).length;
if (answeredQuestions === 0) {
alert('Please answer at least one question before proceeding.');
return;
}
// Prepare complete data for tech stack selector - use ALL features data
const completeData = {
// System-wide information
projectName: projectName,
projectType: projectType,
allFeatures: selectedFeatures, // Include ALL features
businessQuestions: businessQuestions,
businessAnswers: businessAnswers,
timestamp: new Date().toISOString(),
// For backward compatibility with tech-stack-selector
featureName: `${projectName} - Integrated System`,
description: `Complete ${projectType} system with ${selectedFeatures.length} integrated features`,
requirements: selectedFeatures.flatMap(f => f.requirements || []),
complexity: selectedFeatures.some(f => f.complexity === 'high') ? 'high' :
selectedFeatures.some(f => f.complexity === 'medium') ? 'medium' : 'low',
logicRules: selectedFeatures.flatMap(f => f.logicRules || [])
};
console.log('🚀 Sending comprehensive system data to tech stack selector:', completeData);
// Call enhanced tech stack selector directly
const response = await fetch('https://backend.codenuk.com/api/v1/select', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(completeData),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const techRecommendations = await response.json();
console.log('✅ Tech stack recommendations received:', techRecommendations);
// Store results in project store
useProjectStore.setState({
finalProjectData: completeData,
techStackRecommendations: techRecommendations,
businessQuestionsCompleted: true
});
// Move to summary step to show recommendations
setCurrentStep('summary');
} catch (error) {
console.error('❌ Error calling tech stack selector:', error);
alert(`Failed to get technology recommendations: ${error.message}`);
} finally {
setIsSubmitting(false);
}
};
const handleBack = () => {
setCurrentStep('features');
};
if (isLoadingQuestions) {
return (
<div className="flex items-center justify-center min-h-96">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p className="text-gray-600">🧠 AI is generating comprehensive business questions...</p>
<p className="text-gray-500 text-sm mt-2">Analyzing {selectedFeatures.length} features as integrated system</p>
</div>
</div>
);
}
if (error) {
return (
<div className="text-center py-12">
<div className="bg-red-50 border border-red-200 rounded-lg p-6 max-w-md mx-auto">
<h3 className="text-red-900 font-semibold mb-2">Error Loading Questions</h3>
<p className="text-red-700 text-sm mb-4">{error}</p>
<div className="space-x-3">
<button
onClick={loadBusinessQuestions}
className="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 transition-colors"
>
Try Again
</button>
<button
onClick={handleBack}
className="bg-gray-300 text-gray-700 px-4 py-2 rounded-md hover:bg-gray-400 transition-colors"
>
Go Back
</button>
</div>
</div>
</div>
);
}
return (
<div className="space-y-6">
<div className="text-center">
<h2 className="text-2xl font-semibold text-gray-900 mb-2">
📋 Business Context Questions
</h2>
<p className="text-gray-600">
Help us recommend the best technology stack by answering these questions
</p>
<p className="text-sm text-blue-600 mt-1">
Analyzing your complete {projectType} system with {selectedFeatures.length} integrated features
</p>
</div>
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div className="flex items-start space-x-2">
<span className="text-blue-600 text-lg">💡</span>
<div>
<p className="text-blue-800 text-sm">
<strong>Tip:</strong> Answer as many questions as possible for better technology recommendations.
You can skip questions you're unsure about. These questions consider your entire system, not individual features.
</p>
</div>
</div>
</div>
<div className="space-y-6">
{businessQuestions.map((question, index) => (
<div key={index} className="bg-white border border-gray-200 rounded-lg p-6">
<label className="block text-sm font-medium text-gray-900 mb-3">
<span className="inline-flex items-center space-x-2">
<span className="bg-blue-100 text-blue-600 rounded-full w-6 h-6 flex items-center justify-center text-sm font-medium">
{index + 1}
</span>
<span>{question}</span>
</span>
</label>
<textarea
value={businessAnswers[index] || ''}
onChange={(e) => handleAnswerChange(index, e.target.value)}
placeholder="Your answer..."
rows={3}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
))}
</div>
{/* Progress Summary */}
<div className="bg-gray-50 border border-gray-200 rounded-lg p-4">
<h4 className="font-medium text-gray-900 mb-2">Progress Summary</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm text-gray-600">
<div>
<p><strong>Questions answered:</strong> {Object.values(businessAnswers).filter(answer => answer.trim()).length} of {businessQuestions.length}</p>
</div>
<div>
<p><strong>Completion:</strong> {Math.round((Object.values(businessAnswers).filter(answer => answer.trim()).length / businessQuestions.length) * 100)}%</p>
</div>
<div>
<p><strong>Features analyzing:</strong> {selectedFeatures.length} integrated features</p>
</div>
</div>
</div>
{/* Action Buttons */}
<div className="flex justify-between pt-6 border-t border-gray-200">
<button
onClick={handleBack}
className="px-6 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 transition-colors"
>
← Back to Features
</button>
<button
onClick={handleSubmit}
disabled={isSubmitting || Object.values(businessAnswers).filter(answer => answer.trim()).length === 0}
className={`px-6 py-2 rounded-md font-medium transition-colors ${isSubmitting || Object.values(businessAnswers).filter(answer => answer.trim()).length === 0
? 'bg-gray-300 text-gray-500 cursor-not-allowed'
: 'bg-green-600 text-white hover:bg-green-700'
}`}
>
{isSubmitting ? (
<div className="flex items-center space-x-2">
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
<span>Getting System Recommendations...</span>
</div>
) : (
'Generate Technology Recommendations '
)}
</button>
</div>
</div>
);
}