Hma47's picture
Upload 4 files
5fc24c0 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Personalized Community Impact Predictor</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.glass {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(10px);
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
}
.gradient-bg {
background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 50%, #e8f5e8 100%);
min-height: 100vh;
}
.action-card {
transition: all 0.3s ease;
cursor: pointer;
background: rgba(255, 255, 255, 0.9);
border: 2px solid rgba(102, 126, 234, 0.2);
}
.action-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0,0,0,0.15);
background: rgba(255, 255, 255, 0.95);
}
.action-card.selected {
border: 3px solid #10b981;
background: rgba(16, 185, 129, 0.1);
}
.custom-action-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: 2px solid #667eea;
}
.custom-action-card:hover {
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
}
.custom-action-card.selected {
border: 3px solid #10b981;
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
.personalization-form {
background: rgba(255, 255, 255, 0.9);
border-radius: 15px;
padding: 1.5rem;
margin: 1rem 0;
border: 1px solid rgba(102, 126, 234, 0.2);
}
.ai-chat-bubble {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 1rem;
border-radius: 15px;
margin: 0.5rem 0;
position: relative;
}
.ai-chat-bubble::before {
content: "πŸ€–";
position: absolute;
left: -10px;
top: 10px;
background: white;
border-radius: 50%;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.user-input-enhanced {
background: rgba(255, 255, 255, 0.95);
border: 2px solid rgba(102, 126, 234, 0.3);
border-radius: 10px;
padding: 0.75rem;
transition: all 0.3s ease;
color: #374151;
}
.user-input-enhanced:focus {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
outline: none;
}
.progress-step {
display: flex;
align-items: center;
margin: 0.5rem 0;
}
.progress-step.completed {
color: #10b981;
}
.progress-step.active {
color: #667eea;
font-weight: bold;
}
.typing-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background: currentColor;
animation: typing 1.4s infinite ease-in-out;
}
.typing-indicator:nth-child(1) { animation-delay: -0.32s; }
.typing-indicator:nth-child(2) { animation-delay: -0.16s; }
@keyframes typing {
0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
40% { transform: scale(1); opacity: 1; }
}
.country-dropdown {
max-height: 200px;
overflow-y: auto;
background: white;
border: 1px solid #e5e7eb;
border-radius: 8px;
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 50;
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}
.country-option {
padding: 0.75rem;
cursor: pointer;
border-bottom: 1px solid #f3f4f6;
transition: background-color 0.2s;
}
.country-option:hover {
background-color: #f9fafb;
}
.country-option:last-child {
border-bottom: none;
}
.text-dark {
color: #374151 !important;
}
.text-darker {
color: #1f2937 !important;
}
</style>
</head>
<body class="gradient-bg">
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect, useCallback, useRef } = React;
// Global countries list
const COUNTRIES = [
"Afghanistan", "Albania", "Algeria", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan",
"Bahrain", "Bangladesh", "Belarus", "Belgium", "Bolivia", "Bosnia and Herzegovina", "Brazil", "Bulgaria",
"Cambodia", "Canada", "Chile", "China", "Colombia", "Costa Rica", "Croatia", "Czech Republic",
"Denmark", "Dominican Republic", "Ecuador", "Egypt", "Estonia", "Ethiopia", "Finland", "France",
"Georgia", "Germany", "Ghana", "Greece", "Guatemala", "Honduras", "Hungary", "Iceland", "India",
"Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Japan", "Jordan", "Kazakhstan", "Kenya",
"Kuwait", "Latvia", "Lebanon", "Lithuania", "Luxembourg", "Malaysia", "Mexico", "Morocco", "Netherlands",
"New Zealand", "Nigeria", "Norway", "Pakistan", "Peru", "Philippines", "Poland", "Portugal", "Qatar",
"Romania", "Russia", "Saudi Arabia", "Singapore", "Slovakia", "Slovenia", "South Africa", "South Korea",
"Spain", "Sri Lanka", "Sweden", "Switzerland", "Thailand", "Turkey", "Ukraine", "United Arab Emirates",
"United Kingdom", "United States", "Uruguay", "Venezuela", "Vietnam"
];
// Community Action Data with personalization prompts
const COMMUNITY_ACTIONS = {
park: {
title: "Park Redesign",
description: "Redesign local community park with fitness areas and gardens",
icon: "🌳",
category: "Environment & Recreation",
personalQuestions: [
"What is the current condition of parks in your area?",
"What specific improvements would benefit your community most?",
"How often do you and your neighbors use local parks?",
"What age groups in your community would benefit most from park improvements?",
"Are there any cultural or accessibility considerations for your community?"
]
},
traffic: {
title: "Traffic Policy",
description: "Implement new traffic management and safety measures",
icon: "🚦",
category: "Transportation & Safety",
personalQuestions: [
"What are the main traffic issues in your neighborhood?",
"Have you witnessed or experienced traffic-related problems?",
"What times of day are traffic problems most severe in your area?",
"How do current traffic conditions affect your daily life?",
"What specific safety measures would you prioritize?"
]
},
recycling: {
title: "Recycling Initiative",
description: "Launch comprehensive community recycling program",
icon: "♻️",
category: "Environment & Sustainability",
personalQuestions: [
"What recycling facilities currently exist in your community?",
"How does your family currently handle waste and recycling?",
"What are the biggest waste management challenges you observe?",
"How environmentally conscious is your community?",
"What would motivate more people in your area to recycle?"
]
},
housing: {
title: "Affordable Housing",
description: "Develop affordable housing solutions for community",
icon: "🏠",
category: "Housing & Development",
personalQuestions: [
"What is the housing situation like in your community?",
"Do you know people struggling with housing affordability?",
"What types of housing are most needed in your area?",
"How has housing availability changed in recent years?",
"What would make housing more accessible for young people or families?"
]
},
education: {
title: "Educational Program",
description: "Create community education and skill development programs",
icon: "πŸ“š",
category: "Education & Learning",
personalQuestions: [
"What educational resources are available in your community?",
"What skills or knowledge gaps do you see in your area?",
"How could education programs benefit people of different ages?",
"What subjects or skills are you personally interested in learning?",
"How do people in your community typically access learning opportunities?"
]
},
health: {
title: "Health Initiative",
description: "Implement community health and wellness programs",
icon: "❀️",
category: "Health & Wellness",
personalQuestions: [
"What health challenges are common in your community?",
"How accessible are healthcare services in your area?",
"What wellness activities do people in your community enjoy?",
"How has community health been affected by recent events?",
"What would encourage more people to participate in health programs?"
]
},
business: {
title: "Local Business Support",
description: "Support and promote local business development",
icon: "πŸͺ",
category: "Economic Development",
personalQuestions: [
"What types of local businesses exist in your community?",
"How has the local economy been affected by recent changes?",
"What businesses or services are missing from your area?",
"How do you and your family support local businesses?",
"What would help local businesses thrive in your community?"
]
},
safety: {
title: "Community Safety",
description: "Enhance community safety and security measures",
icon: "πŸ›‘οΈ",
category: "Safety & Security",
personalQuestions: [
"How safe do you feel in your community during different times?",
"What safety concerns are most important to address?",
"How do community members currently look out for each other?",
"What would make you feel safer in your neighborhood?",
"How could technology or community programs improve safety?"
]
}
};
// Utility function to safely render content
const safeRender = (content) => {
if (typeof content === 'string') {
return content;
}
if (typeof content === 'object' && content !== null) {
return JSON.stringify(content, null, 2);
}
return String(content);
};
// Component to safely render AI content
const SafeAIContent = ({ content, title }) => {
if (typeof content === 'string') {
return React.createElement('div', { className: "text-white whitespace-pre-line" }, content);
}
if (Array.isArray(content)) {
return React.createElement('div', { className: "space-y-2" },
content.map((item, index) =>
React.createElement('div', { key: index, className: "bg-white bg-opacity-20 rounded-lg p-3" },
React.createElement(SafeAIContent, { content: item })
)
)
);
}
if (typeof content === 'object' && content !== null) {
return React.createElement('div', { className: "bg-white bg-opacity-20 rounded-lg p-3" },
Object.entries(content).map(([key, value]) =>
React.createElement('div', { key: key, className: "mb-2" },
React.createElement('strong', { className: "text-white capitalize" }, key.replace(/_/g, ' ') + ':'),
React.createElement('p', { className: "text-blue-100 mt-1" }, safeRender(value))
)
)
);
}
return React.createElement('div', { className: "text-white" }, safeRender(content));
};
// Error Boundary Component
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({ error, errorInfo });
console.error("Uncaught error:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return React.createElement('div', { className: "glass p-6 m-4 text-center" },
React.createElement('h2', { className: "text-2xl font-bold text-red-600 mb-4" }, "🚨 Application Error"),
React.createElement('p', { className: "text-darker mb-4" },
"Something went wrong. Please try refreshing the page or starting a new prediction."
),
React.createElement('button', {
className: "bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600",
onClick: () => window.location.reload()
}, "Refresh Page")
);
}
return this.props.children;
}
}
// Country Selector Component
const CountrySelector = ({ value, onChange, placeholder = "Select your country..." }) => {
const [isOpen, setIsOpen] = useState(false);
const [searchTerm, setSearchTerm] = useState('');
const dropdownRef = useRef(null);
const filteredCountries = COUNTRIES.filter(country =>
country.toLowerCase().includes(searchTerm.toLowerCase())
);
useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const handleSelect = (country) => {
onChange(country);
setIsOpen(false);
setSearchTerm('');
};
return React.createElement('div', { className: "relative", ref: dropdownRef },
React.createElement('input', {
type: "text",
className: "user-input-enhanced w-full",
placeholder: value || placeholder,
value: searchTerm,
onChange: (e) => setSearchTerm(e.target.value),
onFocus: () => setIsOpen(true),
autoComplete: "off"
}),
isOpen && React.createElement('div', { className: "country-dropdown" },
filteredCountries.length > 0 ?
filteredCountries.map(country =>
React.createElement('div', {
key: country,
className: "country-option text-darker",
onClick: () => handleSelect(country)
}, country)
) :
React.createElement('div', { className: "country-option text-gray-500" }, "No countries found")
)
);
};
// Main Application Component
const CommunityImpactPredictor = () => {
const [currentPhase, setCurrentPhase] = useState(0);
const [selectedAction, setSelectedAction] = useState('');
const [customAction, setCustomAction] = useState({
title: '',
description: '',
category: ''
});
const [isCustomAction, setIsCustomAction] = useState(false);
const [personalContext, setPersonalContext] = useState({
ageRange: '',
country: '',
city: '',
communityType: '',
role: '',
interests: '',
experience: '',
goals: ''
});
const [personalizationAnswers, setPersonalizationAnswers] = useState({});
const [aiInsights, setAiInsights] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [apiKey, setApiKey] = useState('');
const [error, setError] = useState('');
// Phase 0: Personal Context Collection
const renderPersonalContextPhase = () => {
return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
"🌟 Personal Context & Background"
),
React.createElement('p', { className: "text-dark mb-6 text-center" },
"Help us understand your unique perspective and community context for personalized analysis."
),
React.createElement('div', { className: "grid md:grid-cols-2 gap-6" },
// Age Range
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Age Range"),
React.createElement('select', {
className: "user-input-enhanced w-full",
value: personalContext.ageRange,
onChange: (e) => setPersonalContext({...personalContext, ageRange: e.target.value})
},
React.createElement('option', { value: "" }, "Select your age range..."),
React.createElement('option', { value: "13-17" }, "13-17 years"),
React.createElement('option', { value: "18-24" }, "18-24 years"),
React.createElement('option', { value: "25-34" }, "25-34 years"),
React.createElement('option', { value: "35-44" }, "35-44 years"),
React.createElement('option', { value: "45-54" }, "45-54 years"),
React.createElement('option', { value: "55+" }, "55+ years")
)
),
// Country
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Country"),
React.createElement(CountrySelector, {
value: personalContext.country,
onChange: (country) => setPersonalContext({...personalContext, country})
})
),
// City
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "City/Town"),
React.createElement('input', {
type: "text",
className: "user-input-enhanced w-full",
placeholder: "Enter your city or town...",
value: personalContext.city,
onChange: (e) => setPersonalContext({...personalContext, city: e.target.value})
})
),
// Community Type
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Community Type"),
React.createElement('select', {
className: "user-input-enhanced w-full",
value: personalContext.communityType,
onChange: (e) => setPersonalContext({...personalContext, communityType: e.target.value})
},
React.createElement('option', { value: "" }, "Select community type..."),
React.createElement('option', { value: "Urban" }, "Urban (City center)"),
React.createElement('option', { value: "Suburban" }, "Suburban (Residential area)"),
React.createElement('option', { value: "Rural" }, "Rural (Countryside)"),
React.createElement('option', { value: "Small Town" }, "Small Town"),
React.createElement('option', { value: "Village" }, "Village")
)
),
// Role
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Your Role"),
React.createElement('select', {
className: "user-input-enhanced w-full",
value: personalContext.role,
onChange: (e) => setPersonalContext({...personalContext, role: e.target.value})
},
React.createElement('option', { value: "" }, "Select your role..."),
React.createElement('option', { value: "Student" }, "Student"),
React.createElement('option', { value: "Teacher/Educator" }, "Teacher/Educator"),
React.createElement('option', { value: "Community Member" }, "Community Member"),
React.createElement('option', { value: "Local Leader" }, "Local Leader"),
React.createElement('option', { value: "Volunteer" }, "Volunteer"),
React.createElement('option', { value: "Professional" }, "Professional"),
React.createElement('option', { value: "Other" }, "Other")
)
),
// Interests
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Interests & Passions"),
React.createElement('textarea', {
className: "user-input-enhanced w-full h-20",
placeholder: "What causes, hobbies, or topics are you passionate about?",
value: personalContext.interests,
onChange: (e) => setPersonalContext({...personalContext, interests: e.target.value})
})
)
),
React.createElement('div', { className: "mt-6" },
// Experience
React.createElement('div', { className: "mb-4" },
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Community Experience"),
React.createElement('textarea', {
className: "user-input-enhanced w-full h-20",
placeholder: "Describe any previous community involvement, volunteering, or leadership experience...",
value: personalContext.experience,
onChange: (e) => setPersonalContext({...personalContext, experience: e.target.value})
})
),
// Goals
React.createElement('div', { className: "mb-6" },
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Goals & Aspirations"),
React.createElement('textarea', {
className: "user-input-enhanced w-full h-20",
placeholder: "What do you hope to achieve through community engagement? What impact do you want to make?",
value: personalContext.goals,
onChange: (e) => setPersonalContext({...personalContext, goals: e.target.value})
})
)
),
React.createElement('div', { className: "text-center" },
React.createElement('button', {
className: "bg-gradient-to-r from-blue-500 to-purple-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-blue-600 hover:to-purple-700 transition-all duration-300 disabled:opacity-50",
onClick: () => setCurrentPhase(1),
disabled: !personalContext.ageRange || !personalContext.country || !personalContext.city || !personalContext.communityType
}, "Continue to Action Selection β†’")
)
);
};
// Phase 1: Action Selection with Custom Option
const renderActionSelectionPhase = () => {
return React.createElement('div', { className: "glass p-8 max-w-6xl mx-auto" },
React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
"🎯 Select Community Action"
),
React.createElement('p', { className: "text-dark mb-6 text-center" },
"Choose a community action to analyze, or create your own custom initiative."
),
// Preset Actions Grid
React.createElement('div', { className: "grid md:grid-cols-3 lg:grid-cols-4 gap-4 mb-8" },
Object.entries(COMMUNITY_ACTIONS).map(([key, action]) =>
React.createElement('div', {
key: key,
className: `action-card p-4 rounded-lg text-center ${selectedAction === key && !isCustomAction ? 'selected' : ''}`,
onClick: () => {
setSelectedAction(key);
setIsCustomAction(false);
setCustomAction({ title: '', description: '', category: '' });
}
},
React.createElement('div', { className: "text-4xl mb-2" }, action.icon),
React.createElement('h3', { className: "font-bold text-darker mb-1" }, action.title),
React.createElement('p', { className: "text-sm text-dark mb-2" }, action.description),
React.createElement('span', { className: "text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full" }, action.category)
)
)
),
// Custom Action Option
React.createElement('div', { className: "mb-6" },
React.createElement('div', {
className: `custom-action-card action-card p-6 rounded-lg text-center cursor-pointer ${isCustomAction ? 'selected' : ''}`,
onClick: () => {
setIsCustomAction(true);
setSelectedAction('');
}
},
React.createElement('div', { className: "text-4xl mb-2" }, "✨"),
React.createElement('h3', { className: "font-bold mb-2" }, "Create Custom Action"),
React.createElement('p', { className: "text-sm opacity-90" }, "Design your own community initiative")
)
),
// Custom Action Form
isCustomAction && React.createElement('div', { className: "personalization-form mb-6" },
React.createElement('h4', { className: "text-xl font-bold text-darker mb-4" }, "πŸ› οΈ Design Your Custom Action"),
React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-4" },
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Action Title"),
React.createElement('input', {
type: "text",
className: "user-input-enhanced w-full",
placeholder: "e.g., Community Garden Project",
value: customAction.title,
onChange: (e) => setCustomAction({...customAction, title: e.target.value})
})
),
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Category"),
React.createElement('input', {
type: "text",
className: "user-input-enhanced w-full",
placeholder: "e.g., Environment & Sustainability",
value: customAction.category,
onChange: (e) => setCustomAction({...customAction, category: e.target.value})
})
)
),
React.createElement('div', null,
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Description"),
React.createElement('textarea', {
className: "user-input-enhanced w-full h-24",
placeholder: "Describe your community action idea in detail...",
value: customAction.description,
onChange: (e) => setCustomAction({...customAction, description: e.target.value})
})
)
),
React.createElement('div', { className: "flex justify-between" },
React.createElement('button', {
className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
onClick: () => setCurrentPhase(0)
}, "← Back"),
React.createElement('button', {
className: "bg-gradient-to-r from-blue-500 to-purple-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-blue-600 hover:to-purple-700 transition-all duration-300 disabled:opacity-50",
onClick: () => setCurrentPhase(2),
disabled: !selectedAction && (!isCustomAction || !customAction.title || !customAction.description)
}, "Continue to Personalization β†’")
)
);
};
// Phase 2: Personalization Questions
const renderPersonalizationPhase = () => {
const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
const questions = isCustomAction ? [
"Why is this action important to your community?",
"What specific challenges does this action address in your area?",
"How would this action benefit different groups in your community?",
"What resources or support would be needed to implement this?",
"How does this action align with your personal interests and goals?"
] : currentAction.personalQuestions;
return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
"πŸ€” Personalization Questions"
),
React.createElement('div', { className: "bg-blue-50 p-4 rounded-lg mb-6" },
React.createElement('h3', { className: "text-xl font-bold text-darker mb-2" },
`${currentAction.icon || '✨'} ${currentAction.title}`
),
React.createElement('p', { className: "text-dark" }, currentAction.description),
currentAction.category && React.createElement('span', {
className: "inline-block mt-2 text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full"
}, currentAction.category)
),
React.createElement('div', { className: "space-y-6" },
questions.map((question, index) =>
React.createElement('div', { key: index, className: "personalization-form" },
React.createElement('label', { className: "block text-darker font-semibold mb-3" },
`${index + 1}. ${question}`
),
React.createElement('textarea', {
className: "user-input-enhanced w-full h-24",
placeholder: "Share your thoughts and experiences...",
value: personalizationAnswers[index] || '',
onChange: (e) => setPersonalizationAnswers({
...personalizationAnswers,
[index]: e.target.value
})
})
)
)
),
React.createElement('div', { className: "flex justify-between mt-8" },
React.createElement('button', {
className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
onClick: () => setCurrentPhase(1)
}, "← Back"),
React.createElement('button', {
className: "bg-gradient-to-r from-blue-500 to-purple-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-blue-600 hover:to-purple-700 transition-all duration-300 disabled:opacity-50",
onClick: () => setCurrentPhase(3),
disabled: Object.keys(personalizationAnswers).length < questions.length ||
Object.values(personalizationAnswers).some(answer => !answer.trim())
}, "Continue to AI Analysis β†’")
)
);
};
// Phase 3: AI Analysis Setup
const renderAIAnalysisSetup = () => {
return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
"πŸ€– AI Impact Analysis"
),
React.createElement('p', { className: "text-dark mb-6 text-center" },
"Provide your OpenAI API key to generate personalized community impact predictions."
),
React.createElement('div', { className: "personalization-form mb-6" },
React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "OpenAI API Key"),
React.createElement('input', {
type: "password",
className: "user-input-enhanced w-full",
placeholder: "Enter your OpenAI API key...",
value: apiKey,
onChange: (e) => setApiKey(e.target.value)
}),
React.createElement('p', { className: "text-sm text-dark mt-2" },
"Your API key is stored locally and never transmitted to external servers."
)
),
error && React.createElement('div', { className: "bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4" },
error
),
React.createElement('div', { className: "flex justify-between" },
React.createElement('button', {
className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
onClick: () => setCurrentPhase(2)
}, "← Back"),
React.createElement('button', {
className: "bg-gradient-to-r from-green-500 to-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-green-600 hover:to-blue-700 transition-all duration-300 disabled:opacity-50",
onClick: generateAIInsights,
disabled: !apiKey || isLoading
}, isLoading ? "Generating Analysis..." : "Generate AI Analysis πŸš€")
)
);
};
// Generate AI Insights
const generateAIInsights = async () => {
setIsLoading(true);
setError('');
try {
const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
const prompt = `As an expert community development analyst, provide a comprehensive impact analysis for the following community action:
Action: ${currentAction.title}
Description: ${currentAction.description}
Category: ${currentAction.category || 'Community Development'}
Personal Context:
- Age Range: ${personalContext.ageRange}
- Location: ${personalContext.city}, ${personalContext.country}
- Community Type: ${personalContext.communityType}
- Role: ${personalContext.role}
- Interests: ${personalContext.interests}
- Experience: ${personalContext.experience}
- Goals: ${personalContext.goals}
Personalization Responses:
${Object.entries(personalizationAnswers).map(([index, answer]) => `${parseInt(index) + 1}. ${answer}`).join('\n')}
Please provide a detailed analysis in the following JSON format:
{
"overview": "Comprehensive overview of the action's potential impact",
"shortTermImpacts": ["impact1", "impact2", "impact3"],
"mediumTermImpacts": ["impact1", "impact2", "impact3"],
"longTermImpacts": ["impact1", "impact2", "impact3"],
"challenges": ["challenge1", "challenge2", "challenge3"],
"successFactors": ["factor1", "factor2", "factor3"],
"stakeholders": ["stakeholder1", "stakeholder2", "stakeholder3"],
"resources": ["resource1", "resource2", "resource3"],
"personalizedRecommendations": "Specific recommendations based on their context and responses",
"globalExamples": [
{
"location": "City, Country",
"description": "Brief description of similar successful initiative",
"outcome": "Key outcomes achieved"
}
]
}
Ensure the analysis is specific to their location (${personalContext.city}, ${personalContext.country}) and considers their personal context and responses.`;
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: 'You are an expert community development analyst providing detailed, actionable insights for community initiatives. Always respond with valid JSON format.'
},
{
role: 'user',
content: prompt
}
],
max_tokens: 2000,
temperature: 0.7
})
});
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
const aiResponse = data.choices[0].message.content;
// Parse JSON response
let insights;
try {
const jsonMatch = aiResponse.match(/\{[\s\S]*\}/);
if (jsonMatch) {
insights = JSON.parse(jsonMatch[0]);
} else {
throw new Error("No JSON found in response");
}
} catch (parseError) {
console.error("JSON parsing error:", parseError);
// Fallback to text response
insights = {
overview: aiResponse,
shortTermImpacts: ["Analysis provided in overview"],
mediumTermImpacts: ["Analysis provided in overview"],
longTermImpacts: ["Analysis provided in overview"],
challenges: ["See overview for details"],
successFactors: ["See overview for details"],
stakeholders: ["Community members", "Local government", "Organizations"],
resources: ["Community support", "Funding", "Volunteers"],
personalizedRecommendations: "See overview for personalized insights",
globalExamples: []
};
}
setAiInsights(insights);
setCurrentPhase(4);
} catch (error) {
console.error('Error generating AI insights:', error);
setError(`Failed to generate analysis: ${error.message}`);
} finally {
setIsLoading(false);
}
};
// Phase 4: AI Results Display
const renderAIResults = () => {
if (!aiInsights) return null;
const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
return React.createElement('div', { className: "glass p-8 max-w-6xl mx-auto" },
React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
"πŸ“Š AI Impact Analysis Results"
),
// Action Summary
React.createElement('div', { className: "bg-blue-50 p-4 rounded-lg mb-6" },
React.createElement('h3', { className: "text-xl font-bold text-darker mb-2" },
`${currentAction.icon || '✨'} ${currentAction.title}`
),
React.createElement('p', { className: "text-dark mb-2" }, currentAction.description),
React.createElement('p', { className: "text-sm text-dark" },
`Analysis for: ${personalContext.city}, ${personalContext.country} (${personalContext.communityType})`
)
),
// Overview
React.createElement('div', { className: "ai-chat-bubble mb-6" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🎯 Overview"),
React.createElement(SafeAIContent, { content: aiInsights.overview })
),
// Impact Timeline
React.createElement('div', { className: "grid md:grid-cols-3 gap-4 mb-6" },
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "πŸ“… Short-term (1-6 months)"),
React.createElement(SafeAIContent, { content: aiInsights.shortTermImpacts })
),
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "πŸ“ˆ Medium-term (6-18 months)"),
React.createElement(SafeAIContent, { content: aiInsights.mediumTermImpacts })
),
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🌟 Long-term (18+ months)"),
React.createElement(SafeAIContent, { content: aiInsights.longTermImpacts })
)
),
// Challenges and Success Factors
React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-6" },
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "⚠️ Challenges"),
React.createElement(SafeAIContent, { content: aiInsights.challenges })
),
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "βœ… Success Factors"),
React.createElement(SafeAIContent, { content: aiInsights.successFactors })
)
),
// Stakeholders and Resources
React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-6" },
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "πŸ‘₯ Key Stakeholders"),
React.createElement(SafeAIContent, { content: aiInsights.stakeholders })
),
React.createElement('div', { className: "ai-chat-bubble" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "πŸ› οΈ Required Resources"),
React.createElement(SafeAIContent, { content: aiInsights.resources })
)
),
// Personalized Recommendations
React.createElement('div', { className: "ai-chat-bubble mb-6" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "πŸ’‘ Personalized Recommendations"),
React.createElement(SafeAIContent, { content: aiInsights.personalizedRecommendations })
),
// Global Examples
aiInsights.globalExamples && aiInsights.globalExamples.length > 0 &&
React.createElement('div', { className: "ai-chat-bubble mb-6" },
React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🌍 Global Examples"),
React.createElement(SafeAIContent, { content: aiInsights.globalExamples })
),
React.createElement('div', { className: "text-center" },
React.createElement('button', {
className: "bg-gradient-to-r from-green-500 to-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:from-green-600 hover:to-blue-700 transition-all duration-300 mr-4",
onClick: () => {
setCurrentPhase(0);
setSelectedAction('');
setIsCustomAction(false);
setCustomAction({ title: '', description: '', category: '' });
setPersonalizationAnswers({});
setAiInsights(null);
setPersonalContext({
ageRange: '',
country: '',
city: '',
communityType: '',
role: '',
interests: '',
experience: '',
goals: ''
});
}
}, "πŸ”„ Start New Analysis"),
React.createElement('button', {
className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
onClick: () => setCurrentPhase(3)
}, "← Back to Setup")
)
);
};
// Main render
return React.createElement('div', { className: "min-h-screen p-4" },
React.createElement('div', { className: "max-w-7xl mx-auto" },
React.createElement('header', { className: "text-center mb-8" },
React.createElement('h1', { className: "text-4xl font-bold text-darker mb-2" },
"🏘️ Community Impact Predictor"
),
React.createElement('p', { className: "text-dark text-lg" },
"Analyze and predict the impact of community actions with AI-powered insights"
)
),
// Progress indicator
React.createElement('div', { className: "glass p-4 mb-6 max-w-4xl mx-auto" },
React.createElement('div', { className: "flex justify-between items-center" },
['Personal Context', 'Action Selection', 'Personalization', 'AI Analysis', 'Results'].map((step, index) =>
React.createElement('div', {
key: index,
className: `progress-step ${index < currentPhase ? 'completed' : index === currentPhase ? 'active' : ''}`
},
React.createElement('span', { className: "mr-2" },
index < currentPhase ? 'βœ…' : index === currentPhase ? 'πŸ”„' : 'β­•'
),
React.createElement('span', { className: "text-sm font-medium text-darker" }, step)
)
)
)
),
// Phase content
currentPhase === 0 && renderPersonalContextPhase(),
currentPhase === 1 && renderActionSelectionPhase(),
currentPhase === 2 && renderPersonalizationPhase(),
currentPhase === 3 && renderAIAnalysisSetup(),
currentPhase === 4 && renderAIResults()
)
);
};
// Render the application
ReactDOM.render(
React.createElement(ErrorBoundary, null,
React.createElement(CommunityImpactPredictor)
),
document.getElementById('root')
);
</script>
</body>
</html>