Hma47 commited on
Commit
5fc24c0
·
verified ·
1 Parent(s): 7435c01

Upload 4 files

Browse files
Files changed (4) hide show
  1. Apache License.txt +17 -0
  2. README.md +92 -0
  3. index.html +1059 -0
  4. 📚 Detailed Guide.txt +90 -0
Apache License.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2025 Shift Mind AI Labs
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
README.md ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "🏘️ Community Impact Predictor"
3
+ emoji: "📊"
4
+ colorFrom: "red"
5
+ colorTo: "blue"
6
+ sdk: "static"
7
+ sdk_version: "0.1.0"
8
+ app_file: "index.html"
9
+ pinned: false
10
+ ---
11
+
12
+ # 🏘️ Community Impact Predictor
13
+ **Developed by Shift Mind AI Labs**
14
+
15
+ The Community Impact Predictor is an open-source, browser-based AI tool that empowers students, educators, and community leaders to simulate, personalize, and analyze the local impact of diverse community actions. The tool leverages user context and an OpenAI-powered engine to generate detailed impact predictions, timelines, recommendations, and real-world global parallels.
16
+
17
+ ---
18
+
19
+ ## 🚀 Features
20
+
21
+ - **Personalized Community Analysis:** Input your age, country, city, role, community type, interests, and experience.
22
+ - **Wide Range of Actions:** Choose from 8+ built-in community action scenarios (park redesign, safety, education, health, business, more) or design your own initiative.
23
+ - **Custom AI-Powered Insights:** Get detailed, stage-by-stage analysis—short, medium, and long-term impacts, challenges, stakeholders, and resources needed.
24
+ - **Global & Local Examples:** Learn from real initiatives worldwide, with AI-curated recommendations tailored to your community and profile.
25
+ - **Gamified Progress:** Milestone progress steps, clear interface, and an option to restart or try multiple actions.
26
+ - **Privacy-First:** All processing is client-side; your OpenAI API key and data never leave your browser.
27
+
28
+ ---
29
+
30
+ ## 🛠 How to Use
31
+
32
+ 1. **Open the tool** in your browser (no installation or login needed).
33
+ 2. **Enter your personal context:** Age, country, city, community type, role, and interests.
34
+ 3. **Select or create a community action** to analyze (or build your own).
35
+ 4. **Answer a series of AI-personalization questions** about your chosen action and local situation.
36
+ 5. **Enter your OpenAI API key** (required for analysis; only stored in your browser).
37
+ 6. **Generate your AI impact analysis:** View detailed short/medium/long-term predictions, key stakeholders, resources, and actionable recommendations.
38
+ 7. **Explore global case studies** and real-world parallels.
39
+ 8. **Restart anytime** to explore new actions or different contexts.
40
+
41
+ ---
42
+
43
+ ## 👩‍🏫 For Educators: How the Tool Supports Teaching
44
+
45
+ - **Authentic Inquiry:** Use for project-based learning, civics, service learning, or STEM/social studies units.
46
+ - **Systems Thinking:** Teaches mapping of cause/effect, stakeholders, and prediction of outcomes.
47
+ - **Student Choice:** Supports exploration of issues that matter to each learner.
48
+ - **Portfolio Evidence:** Save analysis results for presentations or digital portfolios.
49
+ - **Safe for School:** No student data is collected or transmitted.
50
+
51
+ ---
52
+
53
+ ## 👨‍🎓 For Students: Benefits & Learning Outcomes
54
+
55
+ - **Agency:** Explore real, relevant actions in your community—choose what matters most to you.
56
+ - **Critical Thinking:** Practice analyzing impact, mapping context, and weighing challenges.
57
+ - **Personalized Advice:** Receive tailored recommendations, success factors, and learn from global parallels.
58
+ - **Reflection & Growth:** Build civic skills and understanding, with each session unique to your journey.
59
+
60
+ ---
61
+
62
+ ## 🔐 Data Privacy Notice
63
+
64
+ - Your OpenAI API key is stored only in your browser.
65
+ - No data is sent to Shift Mind AI Labs, Hugging Face, or third parties.
66
+ - See [www.shiftmind.io](http://www.shiftmind.io) for our privacy policy.
67
+
68
+ ---
69
+
70
+ ## 📄 License
71
+
72
+ Licensed under the [Apache License 2.0](./LICENSE).
73
+
74
+ ---
75
+
76
+ ## 🧠 About Shift Mind AI Labs
77
+
78
+ Shift Mind AI Labs builds ethical, open-source AI tools for education and social innovation.
79
+
80
+ 🌐 www.shiftmind.io
81
+ ✉️ info@shiftmind.io
82
+
83
+ ---
84
+
85
+ ## 🙌 Contributing
86
+
87
+ Pull requests, feedback, and collaborations are welcome!
88
+ For pilots or integrations: **info@shiftmind.io**
89
+
90
+ ---
91
+
92
+ *Simulate, plan, and predict positive change—one community at a time.*
index.html ADDED
@@ -0,0 +1,1059 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Personalized Community Impact Predictor</title>
7
+ <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
8
+ <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
9
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
11
+ <script src="https://cdn.tailwindcss.com"></script>
12
+ <style>
13
+ .glass {
14
+ background: rgba(255, 255, 255, 0.85);
15
+ backdrop-filter: blur(10px);
16
+ border-radius: 20px;
17
+ border: 1px solid rgba(255, 255, 255, 0.3);
18
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
19
+ }
20
+
21
+ .gradient-bg {
22
+ background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 50%, #e8f5e8 100%);
23
+ min-height: 100vh;
24
+ }
25
+
26
+ .action-card {
27
+ transition: all 0.3s ease;
28
+ cursor: pointer;
29
+ background: rgba(255, 255, 255, 0.9);
30
+ border: 2px solid rgba(102, 126, 234, 0.2);
31
+ }
32
+
33
+ .action-card:hover {
34
+ transform: translateY(-5px);
35
+ box-shadow: 0 20px 40px rgba(0,0,0,0.15);
36
+ background: rgba(255, 255, 255, 0.95);
37
+ }
38
+
39
+ .action-card.selected {
40
+ border: 3px solid #10b981;
41
+ background: rgba(16, 185, 129, 0.1);
42
+ }
43
+
44
+ .custom-action-card {
45
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
46
+ color: white;
47
+ border: 2px solid #667eea;
48
+ }
49
+
50
+ .custom-action-card:hover {
51
+ background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
52
+ }
53
+
54
+ .custom-action-card.selected {
55
+ border: 3px solid #10b981;
56
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
57
+ }
58
+
59
+ .personalization-form {
60
+ background: rgba(255, 255, 255, 0.9);
61
+ border-radius: 15px;
62
+ padding: 1.5rem;
63
+ margin: 1rem 0;
64
+ border: 1px solid rgba(102, 126, 234, 0.2);
65
+ }
66
+
67
+ .ai-chat-bubble {
68
+ background: linear-gradient(135deg, #667eea, #764ba2);
69
+ color: white;
70
+ padding: 1rem;
71
+ border-radius: 15px;
72
+ margin: 0.5rem 0;
73
+ position: relative;
74
+ }
75
+
76
+ .ai-chat-bubble::before {
77
+ content: "🤖";
78
+ position: absolute;
79
+ left: -10px;
80
+ top: 10px;
81
+ background: white;
82
+ border-radius: 50%;
83
+ width: 30px;
84
+ height: 30px;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ font-size: 16px;
89
+ }
90
+
91
+ .user-input-enhanced {
92
+ background: rgba(255, 255, 255, 0.95);
93
+ border: 2px solid rgba(102, 126, 234, 0.3);
94
+ border-radius: 10px;
95
+ padding: 0.75rem;
96
+ transition: all 0.3s ease;
97
+ color: #374151;
98
+ }
99
+
100
+ .user-input-enhanced:focus {
101
+ border-color: #667eea;
102
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
103
+ outline: none;
104
+ }
105
+
106
+ .progress-step {
107
+ display: flex;
108
+ align-items: center;
109
+ margin: 0.5rem 0;
110
+ }
111
+
112
+ .progress-step.completed {
113
+ color: #10b981;
114
+ }
115
+
116
+ .progress-step.active {
117
+ color: #667eea;
118
+ font-weight: bold;
119
+ }
120
+
121
+ .typing-indicator {
122
+ display: inline-block;
123
+ width: 8px;
124
+ height: 8px;
125
+ border-radius: 50%;
126
+ background: currentColor;
127
+ animation: typing 1.4s infinite ease-in-out;
128
+ }
129
+
130
+ .typing-indicator:nth-child(1) { animation-delay: -0.32s; }
131
+ .typing-indicator:nth-child(2) { animation-delay: -0.16s; }
132
+
133
+ @keyframes typing {
134
+ 0%, 80%, 100% { transform: scale(0); opacity: 0.5; }
135
+ 40% { transform: scale(1); opacity: 1; }
136
+ }
137
+
138
+ .country-dropdown {
139
+ max-height: 200px;
140
+ overflow-y: auto;
141
+ background: white;
142
+ border: 1px solid #e5e7eb;
143
+ border-radius: 8px;
144
+ position: absolute;
145
+ top: 100%;
146
+ left: 0;
147
+ right: 0;
148
+ z-index: 50;
149
+ box-shadow: 0 10px 25px rgba(0,0,0,0.1);
150
+ }
151
+
152
+ .country-option {
153
+ padding: 0.75rem;
154
+ cursor: pointer;
155
+ border-bottom: 1px solid #f3f4f6;
156
+ transition: background-color 0.2s;
157
+ }
158
+
159
+ .country-option:hover {
160
+ background-color: #f9fafb;
161
+ }
162
+
163
+ .country-option:last-child {
164
+ border-bottom: none;
165
+ }
166
+
167
+ .text-dark {
168
+ color: #374151 !important;
169
+ }
170
+
171
+ .text-darker {
172
+ color: #1f2937 !important;
173
+ }
174
+ </style>
175
+ </head>
176
+ <body class="gradient-bg">
177
+ <div id="root"></div>
178
+
179
+ <script type="text/babel">
180
+ const { useState, useEffect, useCallback, useRef } = React;
181
+
182
+ // Global countries list
183
+ const COUNTRIES = [
184
+ "Afghanistan", "Albania", "Algeria", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan",
185
+ "Bahrain", "Bangladesh", "Belarus", "Belgium", "Bolivia", "Bosnia and Herzegovina", "Brazil", "Bulgaria",
186
+ "Cambodia", "Canada", "Chile", "China", "Colombia", "Costa Rica", "Croatia", "Czech Republic",
187
+ "Denmark", "Dominican Republic", "Ecuador", "Egypt", "Estonia", "Ethiopia", "Finland", "France",
188
+ "Georgia", "Germany", "Ghana", "Greece", "Guatemala", "Honduras", "Hungary", "Iceland", "India",
189
+ "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Japan", "Jordan", "Kazakhstan", "Kenya",
190
+ "Kuwait", "Latvia", "Lebanon", "Lithuania", "Luxembourg", "Malaysia", "Mexico", "Morocco", "Netherlands",
191
+ "New Zealand", "Nigeria", "Norway", "Pakistan", "Peru", "Philippines", "Poland", "Portugal", "Qatar",
192
+ "Romania", "Russia", "Saudi Arabia", "Singapore", "Slovakia", "Slovenia", "South Africa", "South Korea",
193
+ "Spain", "Sri Lanka", "Sweden", "Switzerland", "Thailand", "Turkey", "Ukraine", "United Arab Emirates",
194
+ "United Kingdom", "United States", "Uruguay", "Venezuela", "Vietnam"
195
+ ];
196
+
197
+ // Community Action Data with personalization prompts
198
+ const COMMUNITY_ACTIONS = {
199
+ park: {
200
+ title: "Park Redesign",
201
+ description: "Redesign local community park with fitness areas and gardens",
202
+ icon: "🌳",
203
+ category: "Environment & Recreation",
204
+ personalQuestions: [
205
+ "What is the current condition of parks in your area?",
206
+ "What specific improvements would benefit your community most?",
207
+ "How often do you and your neighbors use local parks?",
208
+ "What age groups in your community would benefit most from park improvements?",
209
+ "Are there any cultural or accessibility considerations for your community?"
210
+ ]
211
+ },
212
+ traffic: {
213
+ title: "Traffic Policy",
214
+ description: "Implement new traffic management and safety measures",
215
+ icon: "🚦",
216
+ category: "Transportation & Safety",
217
+ personalQuestions: [
218
+ "What are the main traffic issues in your neighborhood?",
219
+ "Have you witnessed or experienced traffic-related problems?",
220
+ "What times of day are traffic problems most severe in your area?",
221
+ "How do current traffic conditions affect your daily life?",
222
+ "What specific safety measures would you prioritize?"
223
+ ]
224
+ },
225
+ recycling: {
226
+ title: "Recycling Initiative",
227
+ description: "Launch comprehensive community recycling program",
228
+ icon: "♻️",
229
+ category: "Environment & Sustainability",
230
+ personalQuestions: [
231
+ "What recycling facilities currently exist in your community?",
232
+ "How does your family currently handle waste and recycling?",
233
+ "What are the biggest waste management challenges you observe?",
234
+ "How environmentally conscious is your community?",
235
+ "What would motivate more people in your area to recycle?"
236
+ ]
237
+ },
238
+ housing: {
239
+ title: "Affordable Housing",
240
+ description: "Develop affordable housing solutions for community",
241
+ icon: "🏠",
242
+ category: "Housing & Development",
243
+ personalQuestions: [
244
+ "What is the housing situation like in your community?",
245
+ "Do you know people struggling with housing affordability?",
246
+ "What types of housing are most needed in your area?",
247
+ "How has housing availability changed in recent years?",
248
+ "What would make housing more accessible for young people or families?"
249
+ ]
250
+ },
251
+ education: {
252
+ title: "Educational Program",
253
+ description: "Create community education and skill development programs",
254
+ icon: "📚",
255
+ category: "Education & Learning",
256
+ personalQuestions: [
257
+ "What educational resources are available in your community?",
258
+ "What skills or knowledge gaps do you see in your area?",
259
+ "How could education programs benefit people of different ages?",
260
+ "What subjects or skills are you personally interested in learning?",
261
+ "How do people in your community typically access learning opportunities?"
262
+ ]
263
+ },
264
+ health: {
265
+ title: "Health Initiative",
266
+ description: "Implement community health and wellness programs",
267
+ icon: "❤️",
268
+ category: "Health & Wellness",
269
+ personalQuestions: [
270
+ "What health challenges are common in your community?",
271
+ "How accessible are healthcare services in your area?",
272
+ "What wellness activities do people in your community enjoy?",
273
+ "How has community health been affected by recent events?",
274
+ "What would encourage more people to participate in health programs?"
275
+ ]
276
+ },
277
+ business: {
278
+ title: "Local Business Support",
279
+ description: "Support and promote local business development",
280
+ icon: "🏪",
281
+ category: "Economic Development",
282
+ personalQuestions: [
283
+ "What types of local businesses exist in your community?",
284
+ "How has the local economy been affected by recent changes?",
285
+ "What businesses or services are missing from your area?",
286
+ "How do you and your family support local businesses?",
287
+ "What would help local businesses thrive in your community?"
288
+ ]
289
+ },
290
+ safety: {
291
+ title: "Community Safety",
292
+ description: "Enhance community safety and security measures",
293
+ icon: "🛡️",
294
+ category: "Safety & Security",
295
+ personalQuestions: [
296
+ "How safe do you feel in your community during different times?",
297
+ "What safety concerns are most important to address?",
298
+ "How do community members currently look out for each other?",
299
+ "What would make you feel safer in your neighborhood?",
300
+ "How could technology or community programs improve safety?"
301
+ ]
302
+ }
303
+ };
304
+
305
+ // Utility function to safely render content
306
+ const safeRender = (content) => {
307
+ if (typeof content === 'string') {
308
+ return content;
309
+ }
310
+ if (typeof content === 'object' && content !== null) {
311
+ return JSON.stringify(content, null, 2);
312
+ }
313
+ return String(content);
314
+ };
315
+
316
+ // Component to safely render AI content
317
+ const SafeAIContent = ({ content, title }) => {
318
+ if (typeof content === 'string') {
319
+ return React.createElement('div', { className: "text-white whitespace-pre-line" }, content);
320
+ }
321
+
322
+ if (Array.isArray(content)) {
323
+ return React.createElement('div', { className: "space-y-2" },
324
+ content.map((item, index) =>
325
+ React.createElement('div', { key: index, className: "bg-white bg-opacity-20 rounded-lg p-3" },
326
+ React.createElement(SafeAIContent, { content: item })
327
+ )
328
+ )
329
+ );
330
+ }
331
+
332
+ if (typeof content === 'object' && content !== null) {
333
+ return React.createElement('div', { className: "bg-white bg-opacity-20 rounded-lg p-3" },
334
+ Object.entries(content).map(([key, value]) =>
335
+ React.createElement('div', { key: key, className: "mb-2" },
336
+ React.createElement('strong', { className: "text-white capitalize" }, key.replace(/_/g, ' ') + ':'),
337
+ React.createElement('p', { className: "text-blue-100 mt-1" }, safeRender(value))
338
+ )
339
+ )
340
+ );
341
+ }
342
+
343
+ return React.createElement('div', { className: "text-white" }, safeRender(content));
344
+ };
345
+
346
+ // Error Boundary Component
347
+ class ErrorBoundary extends React.Component {
348
+ constructor(props) {
349
+ super(props);
350
+ this.state = { hasError: false, error: null, errorInfo: null };
351
+ }
352
+
353
+ static getDerivedStateFromError(error) {
354
+ return { hasError: true };
355
+ }
356
+
357
+ componentDidCatch(error, errorInfo) {
358
+ this.setState({ error, errorInfo });
359
+ console.error("Uncaught error:", error, errorInfo);
360
+ }
361
+
362
+ render() {
363
+ if (this.state.hasError) {
364
+ return React.createElement('div', { className: "glass p-6 m-4 text-center" },
365
+ React.createElement('h2', { className: "text-2xl font-bold text-red-600 mb-4" }, "🚨 Application Error"),
366
+ React.createElement('p', { className: "text-darker mb-4" },
367
+ "Something went wrong. Please try refreshing the page or starting a new prediction."
368
+ ),
369
+ React.createElement('button', {
370
+ className: "bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600",
371
+ onClick: () => window.location.reload()
372
+ }, "Refresh Page")
373
+ );
374
+ }
375
+ return this.props.children;
376
+ }
377
+ }
378
+
379
+ // Country Selector Component
380
+ const CountrySelector = ({ value, onChange, placeholder = "Select your country..." }) => {
381
+ const [isOpen, setIsOpen] = useState(false);
382
+ const [searchTerm, setSearchTerm] = useState('');
383
+ const dropdownRef = useRef(null);
384
+
385
+ const filteredCountries = COUNTRIES.filter(country =>
386
+ country.toLowerCase().includes(searchTerm.toLowerCase())
387
+ );
388
+
389
+ useEffect(() => {
390
+ const handleClickOutside = (event) => {
391
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
392
+ setIsOpen(false);
393
+ }
394
+ };
395
+
396
+ document.addEventListener('mousedown', handleClickOutside);
397
+ return () => document.removeEventListener('mousedown', handleClickOutside);
398
+ }, []);
399
+
400
+ const handleSelect = (country) => {
401
+ onChange(country);
402
+ setIsOpen(false);
403
+ setSearchTerm('');
404
+ };
405
+
406
+ return React.createElement('div', { className: "relative", ref: dropdownRef },
407
+ React.createElement('input', {
408
+ type: "text",
409
+ className: "user-input-enhanced w-full",
410
+ placeholder: value || placeholder,
411
+ value: searchTerm,
412
+ onChange: (e) => setSearchTerm(e.target.value),
413
+ onFocus: () => setIsOpen(true),
414
+ autoComplete: "off"
415
+ }),
416
+ isOpen && React.createElement('div', { className: "country-dropdown" },
417
+ filteredCountries.length > 0 ?
418
+ filteredCountries.map(country =>
419
+ React.createElement('div', {
420
+ key: country,
421
+ className: "country-option text-darker",
422
+ onClick: () => handleSelect(country)
423
+ }, country)
424
+ ) :
425
+ React.createElement('div', { className: "country-option text-gray-500" }, "No countries found")
426
+ )
427
+ );
428
+ };
429
+
430
+ // Main Application Component
431
+ const CommunityImpactPredictor = () => {
432
+ const [currentPhase, setCurrentPhase] = useState(0);
433
+ const [selectedAction, setSelectedAction] = useState('');
434
+ const [customAction, setCustomAction] = useState({
435
+ title: '',
436
+ description: '',
437
+ category: ''
438
+ });
439
+ const [isCustomAction, setIsCustomAction] = useState(false);
440
+ const [personalContext, setPersonalContext] = useState({
441
+ ageRange: '',
442
+ country: '',
443
+ city: '',
444
+ communityType: '',
445
+ role: '',
446
+ interests: '',
447
+ experience: '',
448
+ goals: ''
449
+ });
450
+ const [personalizationAnswers, setPersonalizationAnswers] = useState({});
451
+ const [aiInsights, setAiInsights] = useState(null);
452
+ const [isLoading, setIsLoading] = useState(false);
453
+ const [apiKey, setApiKey] = useState('');
454
+ const [error, setError] = useState('');
455
+
456
+ // Phase 0: Personal Context Collection
457
+ const renderPersonalContextPhase = () => {
458
+ return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
459
+ React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
460
+ "🌟 Personal Context & Background"
461
+ ),
462
+ React.createElement('p', { className: "text-dark mb-6 text-center" },
463
+ "Help us understand your unique perspective and community context for personalized analysis."
464
+ ),
465
+
466
+ React.createElement('div', { className: "grid md:grid-cols-2 gap-6" },
467
+ // Age Range
468
+ React.createElement('div', null,
469
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Age Range"),
470
+ React.createElement('select', {
471
+ className: "user-input-enhanced w-full",
472
+ value: personalContext.ageRange,
473
+ onChange: (e) => setPersonalContext({...personalContext, ageRange: e.target.value})
474
+ },
475
+ React.createElement('option', { value: "" }, "Select your age range..."),
476
+ React.createElement('option', { value: "13-17" }, "13-17 years"),
477
+ React.createElement('option', { value: "18-24" }, "18-24 years"),
478
+ React.createElement('option', { value: "25-34" }, "25-34 years"),
479
+ React.createElement('option', { value: "35-44" }, "35-44 years"),
480
+ React.createElement('option', { value: "45-54" }, "45-54 years"),
481
+ React.createElement('option', { value: "55+" }, "55+ years")
482
+ )
483
+ ),
484
+
485
+ // Country
486
+ React.createElement('div', null,
487
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Country"),
488
+ React.createElement(CountrySelector, {
489
+ value: personalContext.country,
490
+ onChange: (country) => setPersonalContext({...personalContext, country})
491
+ })
492
+ ),
493
+
494
+ // City
495
+ React.createElement('div', null,
496
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "City/Town"),
497
+ React.createElement('input', {
498
+ type: "text",
499
+ className: "user-input-enhanced w-full",
500
+ placeholder: "Enter your city or town...",
501
+ value: personalContext.city,
502
+ onChange: (e) => setPersonalContext({...personalContext, city: e.target.value})
503
+ })
504
+ ),
505
+
506
+ // Community Type
507
+ React.createElement('div', null,
508
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Community Type"),
509
+ React.createElement('select', {
510
+ className: "user-input-enhanced w-full",
511
+ value: personalContext.communityType,
512
+ onChange: (e) => setPersonalContext({...personalContext, communityType: e.target.value})
513
+ },
514
+ React.createElement('option', { value: "" }, "Select community type..."),
515
+ React.createElement('option', { value: "Urban" }, "Urban (City center)"),
516
+ React.createElement('option', { value: "Suburban" }, "Suburban (Residential area)"),
517
+ React.createElement('option', { value: "Rural" }, "Rural (Countryside)"),
518
+ React.createElement('option', { value: "Small Town" }, "Small Town"),
519
+ React.createElement('option', { value: "Village" }, "Village")
520
+ )
521
+ ),
522
+
523
+ // Role
524
+ React.createElement('div', null,
525
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Your Role"),
526
+ React.createElement('select', {
527
+ className: "user-input-enhanced w-full",
528
+ value: personalContext.role,
529
+ onChange: (e) => setPersonalContext({...personalContext, role: e.target.value})
530
+ },
531
+ React.createElement('option', { value: "" }, "Select your role..."),
532
+ React.createElement('option', { value: "Student" }, "Student"),
533
+ React.createElement('option', { value: "Teacher/Educator" }, "Teacher/Educator"),
534
+ React.createElement('option', { value: "Community Member" }, "Community Member"),
535
+ React.createElement('option', { value: "Local Leader" }, "Local Leader"),
536
+ React.createElement('option', { value: "Volunteer" }, "Volunteer"),
537
+ React.createElement('option', { value: "Professional" }, "Professional"),
538
+ React.createElement('option', { value: "Other" }, "Other")
539
+ )
540
+ ),
541
+
542
+ // Interests
543
+ React.createElement('div', null,
544
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Interests & Passions"),
545
+ React.createElement('textarea', {
546
+ className: "user-input-enhanced w-full h-20",
547
+ placeholder: "What causes, hobbies, or topics are you passionate about?",
548
+ value: personalContext.interests,
549
+ onChange: (e) => setPersonalContext({...personalContext, interests: e.target.value})
550
+ })
551
+ )
552
+ ),
553
+
554
+ React.createElement('div', { className: "mt-6" },
555
+ // Experience
556
+ React.createElement('div', { className: "mb-4" },
557
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Community Experience"),
558
+ React.createElement('textarea', {
559
+ className: "user-input-enhanced w-full h-20",
560
+ placeholder: "Describe any previous community involvement, volunteering, or leadership experience...",
561
+ value: personalContext.experience,
562
+ onChange: (e) => setPersonalContext({...personalContext, experience: e.target.value})
563
+ })
564
+ ),
565
+
566
+ // Goals
567
+ React.createElement('div', { className: "mb-6" },
568
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Goals & Aspirations"),
569
+ React.createElement('textarea', {
570
+ className: "user-input-enhanced w-full h-20",
571
+ placeholder: "What do you hope to achieve through community engagement? What impact do you want to make?",
572
+ value: personalContext.goals,
573
+ onChange: (e) => setPersonalContext({...personalContext, goals: e.target.value})
574
+ })
575
+ )
576
+ ),
577
+
578
+ React.createElement('div', { className: "text-center" },
579
+ React.createElement('button', {
580
+ 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",
581
+ onClick: () => setCurrentPhase(1),
582
+ disabled: !personalContext.ageRange || !personalContext.country || !personalContext.city || !personalContext.communityType
583
+ }, "Continue to Action Selection →")
584
+ )
585
+ );
586
+ };
587
+
588
+ // Phase 1: Action Selection with Custom Option
589
+ const renderActionSelectionPhase = () => {
590
+ return React.createElement('div', { className: "glass p-8 max-w-6xl mx-auto" },
591
+ React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
592
+ "🎯 Select Community Action"
593
+ ),
594
+ React.createElement('p', { className: "text-dark mb-6 text-center" },
595
+ "Choose a community action to analyze, or create your own custom initiative."
596
+ ),
597
+
598
+ // Preset Actions Grid
599
+ React.createElement('div', { className: "grid md:grid-cols-3 lg:grid-cols-4 gap-4 mb-8" },
600
+ Object.entries(COMMUNITY_ACTIONS).map(([key, action]) =>
601
+ React.createElement('div', {
602
+ key: key,
603
+ className: `action-card p-4 rounded-lg text-center ${selectedAction === key && !isCustomAction ? 'selected' : ''}`,
604
+ onClick: () => {
605
+ setSelectedAction(key);
606
+ setIsCustomAction(false);
607
+ setCustomAction({ title: '', description: '', category: '' });
608
+ }
609
+ },
610
+ React.createElement('div', { className: "text-4xl mb-2" }, action.icon),
611
+ React.createElement('h3', { className: "font-bold text-darker mb-1" }, action.title),
612
+ React.createElement('p', { className: "text-sm text-dark mb-2" }, action.description),
613
+ React.createElement('span', { className: "text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full" }, action.category)
614
+ )
615
+ )
616
+ ),
617
+
618
+ // Custom Action Option
619
+ React.createElement('div', { className: "mb-6" },
620
+ React.createElement('div', {
621
+ className: `custom-action-card action-card p-6 rounded-lg text-center cursor-pointer ${isCustomAction ? 'selected' : ''}`,
622
+ onClick: () => {
623
+ setIsCustomAction(true);
624
+ setSelectedAction('');
625
+ }
626
+ },
627
+ React.createElement('div', { className: "text-4xl mb-2" }, "✨"),
628
+ React.createElement('h3', { className: "font-bold mb-2" }, "Create Custom Action"),
629
+ React.createElement('p', { className: "text-sm opacity-90" }, "Design your own community initiative")
630
+ )
631
+ ),
632
+
633
+ // Custom Action Form
634
+ isCustomAction && React.createElement('div', { className: "personalization-form mb-6" },
635
+ React.createElement('h4', { className: "text-xl font-bold text-darker mb-4" }, "🛠️ Design Your Custom Action"),
636
+ React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-4" },
637
+ React.createElement('div', null,
638
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Action Title"),
639
+ React.createElement('input', {
640
+ type: "text",
641
+ className: "user-input-enhanced w-full",
642
+ placeholder: "e.g., Community Garden Project",
643
+ value: customAction.title,
644
+ onChange: (e) => setCustomAction({...customAction, title: e.target.value})
645
+ })
646
+ ),
647
+ React.createElement('div', null,
648
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Category"),
649
+ React.createElement('input', {
650
+ type: "text",
651
+ className: "user-input-enhanced w-full",
652
+ placeholder: "e.g., Environment & Sustainability",
653
+ value: customAction.category,
654
+ onChange: (e) => setCustomAction({...customAction, category: e.target.value})
655
+ })
656
+ )
657
+ ),
658
+ React.createElement('div', null,
659
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "Description"),
660
+ React.createElement('textarea', {
661
+ className: "user-input-enhanced w-full h-24",
662
+ placeholder: "Describe your community action idea in detail...",
663
+ value: customAction.description,
664
+ onChange: (e) => setCustomAction({...customAction, description: e.target.value})
665
+ })
666
+ )
667
+ ),
668
+
669
+ React.createElement('div', { className: "flex justify-between" },
670
+ React.createElement('button', {
671
+ className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
672
+ onClick: () => setCurrentPhase(0)
673
+ }, "← Back"),
674
+ React.createElement('button', {
675
+ 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",
676
+ onClick: () => setCurrentPhase(2),
677
+ disabled: !selectedAction && (!isCustomAction || !customAction.title || !customAction.description)
678
+ }, "Continue to Personalization →")
679
+ )
680
+ );
681
+ };
682
+
683
+ // Phase 2: Personalization Questions
684
+ const renderPersonalizationPhase = () => {
685
+ const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
686
+ const questions = isCustomAction ? [
687
+ "Why is this action important to your community?",
688
+ "What specific challenges does this action address in your area?",
689
+ "How would this action benefit different groups in your community?",
690
+ "What resources or support would be needed to implement this?",
691
+ "How does this action align with your personal interests and goals?"
692
+ ] : currentAction.personalQuestions;
693
+
694
+ return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
695
+ React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
696
+ "🤔 Personalization Questions"
697
+ ),
698
+ React.createElement('div', { className: "bg-blue-50 p-4 rounded-lg mb-6" },
699
+ React.createElement('h3', { className: "text-xl font-bold text-darker mb-2" },
700
+ `${currentAction.icon || '✨'} ${currentAction.title}`
701
+ ),
702
+ React.createElement('p', { className: "text-dark" }, currentAction.description),
703
+ currentAction.category && React.createElement('span', {
704
+ className: "inline-block mt-2 text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full"
705
+ }, currentAction.category)
706
+ ),
707
+
708
+ React.createElement('div', { className: "space-y-6" },
709
+ questions.map((question, index) =>
710
+ React.createElement('div', { key: index, className: "personalization-form" },
711
+ React.createElement('label', { className: "block text-darker font-semibold mb-3" },
712
+ `${index + 1}. ${question}`
713
+ ),
714
+ React.createElement('textarea', {
715
+ className: "user-input-enhanced w-full h-24",
716
+ placeholder: "Share your thoughts and experiences...",
717
+ value: personalizationAnswers[index] || '',
718
+ onChange: (e) => setPersonalizationAnswers({
719
+ ...personalizationAnswers,
720
+ [index]: e.target.value
721
+ })
722
+ })
723
+ )
724
+ )
725
+ ),
726
+
727
+ React.createElement('div', { className: "flex justify-between mt-8" },
728
+ React.createElement('button', {
729
+ className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
730
+ onClick: () => setCurrentPhase(1)
731
+ }, "← Back"),
732
+ React.createElement('button', {
733
+ 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",
734
+ onClick: () => setCurrentPhase(3),
735
+ disabled: Object.keys(personalizationAnswers).length < questions.length ||
736
+ Object.values(personalizationAnswers).some(answer => !answer.trim())
737
+ }, "Continue to AI Analysis →")
738
+ )
739
+ );
740
+ };
741
+
742
+ // Phase 3: AI Analysis Setup
743
+ const renderAIAnalysisSetup = () => {
744
+ return React.createElement('div', { className: "glass p-8 max-w-4xl mx-auto" },
745
+ React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
746
+ "🤖 AI Impact Analysis"
747
+ ),
748
+ React.createElement('p', { className: "text-dark mb-6 text-center" },
749
+ "Provide your OpenAI API key to generate personalized community impact predictions."
750
+ ),
751
+
752
+ React.createElement('div', { className: "personalization-form mb-6" },
753
+ React.createElement('label', { className: "block text-darker font-semibold mb-2" }, "OpenAI API Key"),
754
+ React.createElement('input', {
755
+ type: "password",
756
+ className: "user-input-enhanced w-full",
757
+ placeholder: "Enter your OpenAI API key...",
758
+ value: apiKey,
759
+ onChange: (e) => setApiKey(e.target.value)
760
+ }),
761
+ React.createElement('p', { className: "text-sm text-dark mt-2" },
762
+ "Your API key is stored locally and never transmitted to external servers."
763
+ )
764
+ ),
765
+
766
+ error && React.createElement('div', { className: "bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4" },
767
+ error
768
+ ),
769
+
770
+ React.createElement('div', { className: "flex justify-between" },
771
+ React.createElement('button', {
772
+ className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
773
+ onClick: () => setCurrentPhase(2)
774
+ }, "← Back"),
775
+ React.createElement('button', {
776
+ 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",
777
+ onClick: generateAIInsights,
778
+ disabled: !apiKey || isLoading
779
+ }, isLoading ? "Generating Analysis..." : "Generate AI Analysis 🚀")
780
+ )
781
+ );
782
+ };
783
+
784
+ // Generate AI Insights
785
+ const generateAIInsights = async () => {
786
+ setIsLoading(true);
787
+ setError('');
788
+
789
+ try {
790
+ const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
791
+
792
+ const prompt = `As an expert community development analyst, provide a comprehensive impact analysis for the following community action:
793
+
794
+ Action: ${currentAction.title}
795
+ Description: ${currentAction.description}
796
+ Category: ${currentAction.category || 'Community Development'}
797
+
798
+ Personal Context:
799
+ - Age Range: ${personalContext.ageRange}
800
+ - Location: ${personalContext.city}, ${personalContext.country}
801
+ - Community Type: ${personalContext.communityType}
802
+ - Role: ${personalContext.role}
803
+ - Interests: ${personalContext.interests}
804
+ - Experience: ${personalContext.experience}
805
+ - Goals: ${personalContext.goals}
806
+
807
+ Personalization Responses:
808
+ ${Object.entries(personalizationAnswers).map(([index, answer]) => `${parseInt(index) + 1}. ${answer}`).join('\n')}
809
+
810
+ Please provide a detailed analysis in the following JSON format:
811
+ {
812
+ "overview": "Comprehensive overview of the action's potential impact",
813
+ "shortTermImpacts": ["impact1", "impact2", "impact3"],
814
+ "mediumTermImpacts": ["impact1", "impact2", "impact3"],
815
+ "longTermImpacts": ["impact1", "impact2", "impact3"],
816
+ "challenges": ["challenge1", "challenge2", "challenge3"],
817
+ "successFactors": ["factor1", "factor2", "factor3"],
818
+ "stakeholders": ["stakeholder1", "stakeholder2", "stakeholder3"],
819
+ "resources": ["resource1", "resource2", "resource3"],
820
+ "personalizedRecommendations": "Specific recommendations based on their context and responses",
821
+ "globalExamples": [
822
+ {
823
+ "location": "City, Country",
824
+ "description": "Brief description of similar successful initiative",
825
+ "outcome": "Key outcomes achieved"
826
+ }
827
+ ]
828
+ }
829
+
830
+ Ensure the analysis is specific to their location (${personalContext.city}, ${personalContext.country}) and considers their personal context and responses.`;
831
+
832
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
833
+ method: 'POST',
834
+ headers: {
835
+ 'Content-Type': 'application/json',
836
+ 'Authorization': `Bearer ${apiKey}`
837
+ },
838
+ body: JSON.stringify({
839
+ model: 'gpt-4o-mini',
840
+ messages: [
841
+ {
842
+ role: 'system',
843
+ content: 'You are an expert community development analyst providing detailed, actionable insights for community initiatives. Always respond with valid JSON format.'
844
+ },
845
+ {
846
+ role: 'user',
847
+ content: prompt
848
+ }
849
+ ],
850
+ max_tokens: 2000,
851
+ temperature: 0.7
852
+ })
853
+ });
854
+
855
+ if (!response.ok) {
856
+ throw new Error(`API Error: ${response.status} ${response.statusText}`);
857
+ }
858
+
859
+ const data = await response.json();
860
+ const aiResponse = data.choices[0].message.content;
861
+
862
+ // Parse JSON response
863
+ let insights;
864
+ try {
865
+ const jsonMatch = aiResponse.match(/\{[\s\S]*\}/);
866
+ if (jsonMatch) {
867
+ insights = JSON.parse(jsonMatch[0]);
868
+ } else {
869
+ throw new Error("No JSON found in response");
870
+ }
871
+ } catch (parseError) {
872
+ console.error("JSON parsing error:", parseError);
873
+ // Fallback to text response
874
+ insights = {
875
+ overview: aiResponse,
876
+ shortTermImpacts: ["Analysis provided in overview"],
877
+ mediumTermImpacts: ["Analysis provided in overview"],
878
+ longTermImpacts: ["Analysis provided in overview"],
879
+ challenges: ["See overview for details"],
880
+ successFactors: ["See overview for details"],
881
+ stakeholders: ["Community members", "Local government", "Organizations"],
882
+ resources: ["Community support", "Funding", "Volunteers"],
883
+ personalizedRecommendations: "See overview for personalized insights",
884
+ globalExamples: []
885
+ };
886
+ }
887
+
888
+ setAiInsights(insights);
889
+ setCurrentPhase(4);
890
+
891
+ } catch (error) {
892
+ console.error('Error generating AI insights:', error);
893
+ setError(`Failed to generate analysis: ${error.message}`);
894
+ } finally {
895
+ setIsLoading(false);
896
+ }
897
+ };
898
+
899
+ // Phase 4: AI Results Display
900
+ const renderAIResults = () => {
901
+ if (!aiInsights) return null;
902
+
903
+ const currentAction = isCustomAction ? customAction : COMMUNITY_ACTIONS[selectedAction];
904
+
905
+ return React.createElement('div', { className: "glass p-8 max-w-6xl mx-auto" },
906
+ React.createElement('h2', { className: "text-3xl font-bold text-darker mb-6 text-center" },
907
+ "📊 AI Impact Analysis Results"
908
+ ),
909
+
910
+ // Action Summary
911
+ React.createElement('div', { className: "bg-blue-50 p-4 rounded-lg mb-6" },
912
+ React.createElement('h3', { className: "text-xl font-bold text-darker mb-2" },
913
+ `${currentAction.icon || '✨'} ${currentAction.title}`
914
+ ),
915
+ React.createElement('p', { className: "text-dark mb-2" }, currentAction.description),
916
+ React.createElement('p', { className: "text-sm text-dark" },
917
+ `Analysis for: ${personalContext.city}, ${personalContext.country} (${personalContext.communityType})`
918
+ )
919
+ ),
920
+
921
+ // Overview
922
+ React.createElement('div', { className: "ai-chat-bubble mb-6" },
923
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🎯 Overview"),
924
+ React.createElement(SafeAIContent, { content: aiInsights.overview })
925
+ ),
926
+
927
+ // Impact Timeline
928
+ React.createElement('div', { className: "grid md:grid-cols-3 gap-4 mb-6" },
929
+ React.createElement('div', { className: "ai-chat-bubble" },
930
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "📅 Short-term (1-6 months)"),
931
+ React.createElement(SafeAIContent, { content: aiInsights.shortTermImpacts })
932
+ ),
933
+ React.createElement('div', { className: "ai-chat-bubble" },
934
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "📈 Medium-term (6-18 months)"),
935
+ React.createElement(SafeAIContent, { content: aiInsights.mediumTermImpacts })
936
+ ),
937
+ React.createElement('div', { className: "ai-chat-bubble" },
938
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🌟 Long-term (18+ months)"),
939
+ React.createElement(SafeAIContent, { content: aiInsights.longTermImpacts })
940
+ )
941
+ ),
942
+
943
+ // Challenges and Success Factors
944
+ React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-6" },
945
+ React.createElement('div', { className: "ai-chat-bubble" },
946
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "⚠️ Challenges"),
947
+ React.createElement(SafeAIContent, { content: aiInsights.challenges })
948
+ ),
949
+ React.createElement('div', { className: "ai-chat-bubble" },
950
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "✅ Success Factors"),
951
+ React.createElement(SafeAIContent, { content: aiInsights.successFactors })
952
+ )
953
+ ),
954
+
955
+ // Stakeholders and Resources
956
+ React.createElement('div', { className: "grid md:grid-cols-2 gap-4 mb-6" },
957
+ React.createElement('div', { className: "ai-chat-bubble" },
958
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "👥 Key Stakeholders"),
959
+ React.createElement(SafeAIContent, { content: aiInsights.stakeholders })
960
+ ),
961
+ React.createElement('div', { className: "ai-chat-bubble" },
962
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🛠️ Required Resources"),
963
+ React.createElement(SafeAIContent, { content: aiInsights.resources })
964
+ )
965
+ ),
966
+
967
+ // Personalized Recommendations
968
+ React.createElement('div', { className: "ai-chat-bubble mb-6" },
969
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "💡 Personalized Recommendations"),
970
+ React.createElement(SafeAIContent, { content: aiInsights.personalizedRecommendations })
971
+ ),
972
+
973
+ // Global Examples
974
+ aiInsights.globalExamples && aiInsights.globalExamples.length > 0 &&
975
+ React.createElement('div', { className: "ai-chat-bubble mb-6" },
976
+ React.createElement('h4', { className: "text-lg font-bold mb-3" }, "🌍 Global Examples"),
977
+ React.createElement(SafeAIContent, { content: aiInsights.globalExamples })
978
+ ),
979
+
980
+ React.createElement('div', { className: "text-center" },
981
+ React.createElement('button', {
982
+ 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",
983
+ onClick: () => {
984
+ setCurrentPhase(0);
985
+ setSelectedAction('');
986
+ setIsCustomAction(false);
987
+ setCustomAction({ title: '', description: '', category: '' });
988
+ setPersonalizationAnswers({});
989
+ setAiInsights(null);
990
+ setPersonalContext({
991
+ ageRange: '',
992
+ country: '',
993
+ city: '',
994
+ communityType: '',
995
+ role: '',
996
+ interests: '',
997
+ experience: '',
998
+ goals: ''
999
+ });
1000
+ }
1001
+ }, "🔄 Start New Analysis"),
1002
+ React.createElement('button', {
1003
+ className: "bg-gray-500 text-white px-6 py-2 rounded-lg hover:bg-gray-600 transition-colors",
1004
+ onClick: () => setCurrentPhase(3)
1005
+ }, "← Back to Setup")
1006
+ )
1007
+ );
1008
+ };
1009
+
1010
+ // Main render
1011
+ return React.createElement('div', { className: "min-h-screen p-4" },
1012
+ React.createElement('div', { className: "max-w-7xl mx-auto" },
1013
+ React.createElement('header', { className: "text-center mb-8" },
1014
+ React.createElement('h1', { className: "text-4xl font-bold text-darker mb-2" },
1015
+ "🏘️ Community Impact Predictor"
1016
+ ),
1017
+ React.createElement('p', { className: "text-dark text-lg" },
1018
+ "Analyze and predict the impact of community actions with AI-powered insights"
1019
+ )
1020
+ ),
1021
+
1022
+ // Progress indicator
1023
+ React.createElement('div', { className: "glass p-4 mb-6 max-w-4xl mx-auto" },
1024
+ React.createElement('div', { className: "flex justify-between items-center" },
1025
+ ['Personal Context', 'Action Selection', 'Personalization', 'AI Analysis', 'Results'].map((step, index) =>
1026
+ React.createElement('div', {
1027
+ key: index,
1028
+ className: `progress-step ${index < currentPhase ? 'completed' : index === currentPhase ? 'active' : ''}`
1029
+ },
1030
+ React.createElement('span', { className: "mr-2" },
1031
+ index < currentPhase ? '✅' : index === currentPhase ? '🔄' : '⭕'
1032
+ ),
1033
+ React.createElement('span', { className: "text-sm font-medium text-darker" }, step)
1034
+ )
1035
+ )
1036
+ )
1037
+ ),
1038
+
1039
+ // Phase content
1040
+ currentPhase === 0 && renderPersonalContextPhase(),
1041
+ currentPhase === 1 && renderActionSelectionPhase(),
1042
+ currentPhase === 2 && renderPersonalizationPhase(),
1043
+ currentPhase === 3 && renderAIAnalysisSetup(),
1044
+ currentPhase === 4 && renderAIResults()
1045
+ )
1046
+ );
1047
+ };
1048
+
1049
+ // Render the application
1050
+ ReactDOM.render(
1051
+ React.createElement(ErrorBoundary, null,
1052
+ React.createElement(CommunityImpactPredictor)
1053
+ ),
1054
+ document.getElementById('root')
1055
+ );
1056
+ </script>
1057
+ </body>
1058
+ </html>
1059
+
📚 Detailed Guide.txt ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 📚 Detailed Guide: Using the Community Impact Predictor
2
+ 1. Introduction
3
+ The Community Impact Predictor helps users—especially students and educators—explore, personalize, and predict the outcomes of local community initiatives using real-world context and AI-powered analysis.
4
+
5
+ 2. Step-by-Step Instructions
6
+ A. Getting Started
7
+ Access the App:
8
+ Open the Community Impact Predictor in your browser. No login or installation is required.
9
+
10
+ Personal Context Setup:
11
+
12
+ Enter your age range, country, city/town, type of community (urban, rural, etc.), and your role (student, teacher, etc.).
13
+
14
+ Share your interests, experience, and goals for community action.
15
+
16
+ Select or Create an Action:
17
+
18
+ Pick from built-in actions (e.g., Park Redesign, Recycling Initiative, Educational Program, Community Safety).
19
+
20
+ Or design your own community action with a title, category, and description.
21
+
22
+ Personalization Questions:
23
+
24
+ Respond to a set of prompts to help the AI understand your specific local context (e.g., current challenges, resources, needs).
25
+
26
+ For custom actions, describe their unique importance and local relevance.
27
+
28
+ Enter Your OpenAI API Key:
29
+
30
+ Needed to generate the AI-powered analysis (key is stored only in your browser).
31
+
32
+ AI-Powered Analysis:
33
+
34
+ The AI provides a comprehensive, multi-phase report:
35
+
36
+ Overview: Summary of your action’s impact.
37
+
38
+ Short, Medium, Long-Term Predictions: Expected outcomes across different time frames.
39
+
40
+ Challenges & Success Factors: What could help or hinder your initiative.
41
+
42
+ Key Stakeholders & Resources: Who you need to engage and what resources are required.
43
+
44
+ Personalized Recommendations: Tailored steps for your unique context.
45
+
46
+ Global Examples: Real initiatives worldwide with relevant lessons.
47
+
48
+ Review & Reflect:
49
+
50
+ Use your report for project planning, reflection, or as portfolio evidence.
51
+
52
+ Restart to explore new actions, cities, or personal situations.
53
+
54
+ 3. For Teachers: How This Tool Supports Education
55
+ Project-Based Learning:
56
+ Integrate into social studies, civics, environmental science, or enrichment projects.
57
+
58
+ Systems & Critical Thinking:
59
+ Students analyze impact, predict outcomes, and explore the ripple effects of community change.
60
+
61
+ Student Agency:
62
+ Learners take ownership—choose actions that matter to them, build real skills in planning and analysis.
63
+
64
+ Evidence & Assessment:
65
+ Use AI reports as artifacts for assessment, reflection, or parent-teacher conferences.
66
+
67
+ Privacy-First:
68
+ No accounts or external data—safe for all ages and school environments.
69
+
70
+ 4. For Students: Benefits & Outcomes
71
+ Active Citizenship:
72
+ Move from awareness to action—explore real issues, predict solutions, and develop civic agency.
73
+
74
+ Personalized Growth:
75
+ Every analysis is tailored—no generic answers.
76
+
77
+ Collaboration Ready:
78
+ Use in group projects or share results with your class.
79
+
80
+ Portfolio Building:
81
+ Save your reports and global examples as part of your learning journey.
82
+
83
+ 5. Best Practices & Tips
84
+ Try different actions and locations—see how context changes predictions.
85
+
86
+ Use as a starting point for service learning, club projects, or youth initiatives.
87
+
88
+ Collaborate with peers—compare analyses for the same action in different communities.
89
+
90
+ Keep your API key secure and never share it publicly.