gaialive commited on
Commit
17b5182
Β·
verified Β·
1 Parent(s): c3cf510

Update web/src/App.js

Browse files
Files changed (1) hide show
  1. web/src/App.js +513 -513
web/src/App.js CHANGED
@@ -1,514 +1,514 @@
1
- import React, { useState, useEffect } from 'react';
2
- import './App.css';
3
- import { systemInitializer } from './utils/systemInitializer.js';
4
- import { authManager } from './utils/auth.js';
5
- import LoadingScreen from './components/LoadingScreen';
6
-
7
- // Import all your pages
8
- import Dashboard from './pages/Dashboard';
9
- import AquaLens from './pages/AquaLens';
10
- import BiodiversityEar from './pages/BiodiversityEar';
11
- import CarbonOptimizer from './pages/CarbonOptimizer';
12
- import SmartFarming from './pages/SmartFarming';
13
- import EWasteRecycling from './pages/EWasteRecycling';
14
- import AirQuality from './pages/AirQuality';
15
- import FloraShield from './pages/FloraShield';
16
- import FoodWasteReduction from './pages/FoodWasteReduction';
17
- import EnvironmentalJustice from './pages/EnvironmentalJustice';
18
- import EcoSonification from './pages/EcoSonification';
19
- import PhantomFootprint from './pages/PhantomFootprint';
20
- import UpcyclingAgent from './pages/UpcyclingAgent';
21
- import PackagingDesigner from './pages/PackagingDesigner';
22
- import Impact from './pages/Impact';
23
- import EcoTasks from './pages/EcoTasks';
24
- import Learn from './pages/Learn';
25
- import Startups from './pages/Startups';
26
- import Community from './pages/Community';
27
- import Profile from './pages/Profile';
28
- import Login from './pages/Login';
29
- import DigitalQuarry from './pages/DigitalQuarry';
30
- import BioStreamAI from './pages/BioStreamAI';
31
- import EWasteProspector from './pages/EWasteProspector';
32
- import GeneticResilience from './pages/GeneticResilience';
33
-
34
- function App() {
35
- const [activePage, setActivePage] = useState('Dashboard');
36
- const [userStats, setUserStats] = useState({
37
- carbonSaved: 0,
38
- waterTests: 0,
39
- biodiversityScans: 0,
40
- treesPlanted: 0,
41
- wasteReduced: 0,
42
- energySaved: 0
43
- });
44
- const [currentUser, setCurrentUser] = useState(null);
45
- const [systemReady, setSystemReady] = useState(false);
46
- const [systemStatus, setSystemStatus] = useState(null);
47
- const [isLoading, setIsLoading] = useState(true);
48
-
49
- // Initialize advanced systems and authentication on app start
50
- useEffect(() => {
51
- const initializeSystems = async () => {
52
- console.log('πŸš€ GreenPlus by GXS: Initializing Advanced Environmental Systems...');
53
-
54
- try {
55
- const status = await systemInitializer.initialize();
56
- setSystemStatus(status);
57
- setSystemReady(status.overallReady);
58
-
59
- // Initialize authentication
60
- const user = authManager.getCurrentUser();
61
- setCurrentUser(user);
62
-
63
- if (status.overallReady) {
64
- console.log('βœ… GreenPlus by GXS: All systems operational!');
65
- } else {
66
- console.warn('⚠️ GreenPlus by GXS: Running with limited functionality');
67
- }
68
- } catch (error) {
69
- console.error('❌ GreenPlus by GXS: System initialization failed:', error);
70
- setSystemReady(false);
71
- }
72
- };
73
-
74
- initializeSystems();
75
-
76
- // Show loading screen for 2.5 seconds
77
- const loadingTimer = setTimeout(() => {
78
- setIsLoading(false);
79
- }, 2500);
80
-
81
- return () => clearTimeout(loadingTimer);
82
- }, []);
83
-
84
- // Handle authentication changes
85
- const handleAuthChange = (user) => {
86
- setCurrentUser(user);
87
- updateUserStats();
88
- };
89
-
90
- // Update user stats from auth manager
91
- const updateUserStats = () => {
92
- const stats = authManager.getUserStats();
93
-
94
- // Only show demo stats for actual guest users, not logged-in users
95
- const isGuest = currentUser?.isGuest === true;
96
- const isNewGuest = isGuest && !stats.carbonSaved && !stats.waterTests && !stats.biodiversityScans;
97
-
98
- console.log('πŸ”„ App.js updateUserStats called');
99
- console.log('πŸ“Š Raw stats from authManager:', stats);
100
- console.log('πŸ‘€ Current user:', currentUser);
101
- console.log('πŸ†• Is new guest:', isNewGuest);
102
-
103
- const newStats = {
104
- carbonSaved: stats.carbonSaved || (isNewGuest ? 12 : 0),
105
- waterTests: stats.waterTests || (isNewGuest ? 3 : 0),
106
- biodiversityScans: stats.biodiversityScans || (isNewGuest ? 2 : 0),
107
- treesPlanted: stats.treesPlanted || 0,
108
- wasteReduced: stats.wasteReduced || 0,
109
- energySaved: stats.energySaved || 0
110
- };
111
-
112
- console.log('πŸ“ˆ Setting userStats to:', newStats);
113
- setUserStats(newStats);
114
- };
115
-
116
- // Set up periodic stats refresh
117
- useEffect(() => {
118
- // Initial stats load
119
- updateUserStats();
120
-
121
- // Refresh stats every 10 seconds (less frequent to reduce flickering)
122
- const statsInterval = setInterval(updateUserStats, 10000);
123
-
124
- return () => clearInterval(statsInterval);
125
- }, [currentUser]);
126
-
127
- const pages = [
128
- {
129
- id: 'Dashboard',
130
- name: 'Dashboard',
131
- icon: '🏠',
132
- component: Dashboard,
133
- description: 'Overview & Analytics'
134
- },
135
- {
136
- id: 'AquaLens',
137
- name: 'AquaLens',
138
- icon: 'πŸ’§',
139
- component: AquaLens,
140
- description: 'Water Quality Analysis'
141
- },
142
- {
143
- id: 'BiodiversityEar',
144
- name: 'BiodiversityEar',
145
- icon: '🦜',
146
- component: BiodiversityEar,
147
- description: 'Ecosystem Monitoring'
148
- },
149
- {
150
- id: 'CarbonOptimizer',
151
- name: 'Carbon Optimizer',
152
- icon: '🌱',
153
- component: CarbonOptimizer,
154
- description: 'Carbon Footprint Tracking'
155
- },
156
- {
157
- id: 'SmartFarming',
158
- name: 'Smart Farming',
159
- icon: '🌾',
160
- component: SmartFarming,
161
- description: 'Agricultural Intelligence'
162
- },
163
- {
164
- id: 'EWasteRecycling',
165
- name: 'E-Waste Recycling',
166
- icon: '♻️',
167
- component: EWasteRecycling,
168
- description: 'Electronic Waste Management'
169
- },
170
- {
171
- id: 'AirQuality',
172
- name: 'Air Quality',
173
- icon: '🌬️',
174
- component: AirQuality,
175
- description: 'Air Pollution Monitoring'
176
- },
177
- {
178
- id: 'FloraShield',
179
- name: 'FloraShield',
180
- icon: 'πŸ›‘οΈ',
181
- component: FloraShield,
182
- description: 'Plant Disease Detection'
183
- },
184
- {
185
- id: 'FoodWasteReduction',
186
- name: 'Food Waste Reduction',
187
- icon: '🍎',
188
- component: FoodWasteReduction,
189
- description: 'Food Rescue Network'
190
- },
191
- {
192
- id: 'EnvironmentalJustice',
193
- name: 'Environmental Justice',
194
- icon: 'βš–οΈ',
195
- component: EnvironmentalJustice,
196
- description: 'Equity & Justice'
197
- },
198
- {
199
- id: 'EcoSonification',
200
- name: 'EcoSonification',
201
- icon: '🎡',
202
- component: EcoSonification,
203
- description: 'Environmental Sound Art'
204
- },
205
- {
206
- id: 'PhantomFootprint',
207
- name: 'Phantom Footprint',
208
- icon: 'πŸ‘»',
209
- component: PhantomFootprint,
210
- description: 'Hidden Impact Tracker'
211
- },
212
- {
213
- id: 'UpcyclingAgent',
214
- name: 'Upcycling Agent',
215
- icon: 'πŸ”„',
216
- component: UpcyclingAgent,
217
- description: 'Creative Reuse Assistant'
218
- },
219
- {
220
- id: 'PackagingDesigner',
221
- name: 'Packaging Designer',
222
- icon: 'πŸ“¦',
223
- component: PackagingDesigner,
224
- description: 'Sustainable Packaging'
225
- },
226
- {
227
- id: 'DigitalQuarry',
228
- name: 'Digital Quarry',
229
- icon: 'πŸ—οΈ',
230
- component: DigitalQuarry,
231
- description: 'Construction Waste Marketplace'
232
- },
233
- {
234
- id: 'BioStreamAI',
235
- name: 'Bio-Stream AI',
236
- icon: '🧬',
237
- component: BioStreamAI,
238
- description: 'Environmental DNA Analysis'
239
- },
240
- {
241
- id: 'EWasteProspector',
242
- name: 'E-Waste Prospector',
243
- icon: '⚑',
244
- component: EWasteProspector,
245
- description: 'Critical Mineral Recovery'
246
- },
247
- {
248
- id: 'GeneticResilience',
249
- name: 'Genetic Resilience',
250
- icon: '🌾',
251
- component: GeneticResilience,
252
- description: 'Climate Crop Analysis'
253
- },
254
- {
255
- id: 'Impact',
256
- name: 'Global Impact',
257
- icon: '🌍',
258
- component: Impact,
259
- description: 'Environmental Impact Data'
260
- },
261
- {
262
- id: 'EcoTasks',
263
- name: 'Eco Tasks',
264
- icon: 'βœ…',
265
- component: EcoTasks,
266
- description: 'Daily Green Actions'
267
- },
268
- {
269
- id: 'Learn',
270
- name: 'Learn',
271
- icon: 'πŸ“š',
272
- component: Learn,
273
- description: 'Environmental Education'
274
- },
275
- {
276
- id: 'Startups',
277
- name: 'Green Startups',
278
- icon: 'πŸš€',
279
- component: Startups,
280
- description: 'Sustainable Innovation'
281
- },
282
- {
283
- id: 'Community',
284
- name: 'Community',
285
- icon: 'πŸ‘₯',
286
- component: Community,
287
- description: 'Connect with eco champions'
288
- },
289
- {
290
- id: 'Profile',
291
- name: 'My Profile',
292
- icon: 'πŸ‘€',
293
- component: Profile,
294
- description: 'View your environmental impact'
295
- },
296
- {
297
- id: 'Login',
298
- name: 'Login',
299
- icon: 'πŸ”‘',
300
- component: Login,
301
- description: 'Sign in or create account'
302
- }
303
- ];
304
-
305
- // Initialize page from URL on app load
306
- useEffect(() => {
307
- const urlParams = new URLSearchParams(window.location.search);
308
- const pageFromUrl = urlParams.get('page');
309
-
310
- if (pageFromUrl && pages.some(page => page.id === pageFromUrl)) {
311
- setActivePage(pageFromUrl);
312
- } else {
313
- // If no valid page in URL, set default and update URL
314
- const defaultPage = 'Dashboard';
315
- setActivePage(defaultPage);
316
- updateURL(defaultPage);
317
- }
318
- }, []);
319
-
320
- // Function to update URL without page reload
321
- const updateURL = (pageId) => {
322
- const newUrl = `${window.location.pathname}?page=${pageId}`;
323
- window.history.pushState({ page: pageId }, '', newUrl);
324
- };
325
-
326
- // Handle browser back/forward buttons
327
- useEffect(() => {
328
- const handlePopState = (event) => {
329
- const urlParams = new URLSearchParams(window.location.search);
330
- const pageFromUrl = urlParams.get('page') || 'Dashboard';
331
-
332
- if (pages.some(page => page.id === pageFromUrl)) {
333
- setActivePage(pageFromUrl);
334
- }
335
- };
336
-
337
- window.addEventListener('popstate', handlePopState);
338
- return () => window.removeEventListener('popstate', handlePopState);
339
- }, []);
340
-
341
- const currentPage = pages.find(page => page.id === activePage);
342
- const CurrentComponent = currentPage?.component || Dashboard;
343
-
344
- const handlePageChange = (pageId) => {
345
- setActivePage(pageId);
346
- updateURL(pageId);
347
- };
348
-
349
- // Handle activity completion to update stats immediately
350
- const handleActivityComplete = async (activity) => {
351
- console.log('🎯 App.js handleActivityComplete called with:', activity);
352
-
353
- // Log activity through auth manager if activity data is provided
354
- if (activity && activity.type) {
355
- console.log('πŸ“ Logging activity through authManager...');
356
- await authManager.logActivity(activity.description || 'Environmental action', {
357
- type: activity.type,
358
- amount: activity.amount,
359
- points: activity.points || 10
360
- });
361
- console.log('βœ… Activity logged successfully');
362
- }
363
-
364
- // Update stats display
365
- console.log('πŸ”„ Calling updateUserStats after activity completion...');
366
- updateUserStats();
367
- };
368
-
369
- // Show loading screen first
370
- if (isLoading) {
371
- return <LoadingScreen />;
372
- }
373
-
374
- return (
375
- <div className="terra-app">
376
- {/* Sidebar */}
377
- <div className="terra-sidebar open">
378
- {/* Logo */}
379
- <div className="terra-logo">
380
- <div className="logo-container">
381
- <div className="logo-icon">🌿</div>
382
- <div className="logo-text">
383
- <h1>GreenPlus by GXS</h1>
384
- <p>Environmental Intelligence Hub</p>
385
- </div>
386
- </div>
387
- </div>
388
-
389
- {/* Navigation */}
390
- <div className="terra-nav">
391
- {pages.map(page => (
392
- <div
393
- key={page.id}
394
- className={`nav-item ${activePage === page.id ? 'active' : ''}`}
395
- onClick={() => handlePageChange(page.id)}
396
- >
397
- <span className="nav-icon">{page.icon}</span>
398
- <div className="nav-content">
399
- <span className="nav-name">{page.name}</span>
400
- <span className="nav-desc">{page.description}</span>
401
- </div>
402
- </div>
403
- ))}
404
- </div>
405
-
406
-
407
- </div>
408
-
409
- {/* Main Content */}
410
- <div className="terra-main">
411
- {/* Header */}
412
- <div className="terra-header">
413
- <div className="header-left">
414
- <h1 className="page-title">
415
- <span className="title-icon">{currentPage?.icon}</span>
416
- {currentPage?.name}
417
- </h1>
418
- <p className="page-subtitle">{currentPage?.description}</p>
419
- </div>
420
- <div className="header-right">
421
- {/* User Info */}
422
- {currentUser && (
423
- <div style={{
424
- display: 'flex',
425
- alignItems: 'center',
426
- gap: '15px',
427
- marginRight: '20px'
428
- }}>
429
- <div
430
- onClick={() => handlePageChange('Profile')}
431
- style={{
432
- display: 'flex',
433
- alignItems: 'center',
434
- gap: '8px',
435
- background: 'rgba(255,255,255,0.1)',
436
- padding: '8px 15px',
437
- borderRadius: '20px',
438
- cursor: 'pointer',
439
- transition: 'background 0.2s'
440
- }}
441
- onMouseEnter={(e) => e.target.style.background = 'rgba(255,255,255,0.2)'}
442
- onMouseLeave={(e) => e.target.style.background = 'rgba(255,255,255,0.1)'}
443
- title="Click to view profile"
444
- >
445
- <span style={{ fontSize: '1.2rem' }}>{currentUser.avatar}</span>
446
- <span style={{ color: 'white', fontWeight: 'bold' }}>
447
- {currentUser.name}
448
- </span>
449
- {currentUser.isGuest && (
450
- <span style={{
451
- background: '#FF9800',
452
- color: 'white',
453
- padding: '2px 8px',
454
- borderRadius: '10px',
455
- fontSize: '0.7rem'
456
- }}>
457
- GUEST
458
- </span>
459
- )}
460
- </div>
461
- </div>
462
- )}
463
-
464
- <div className="header-stats">
465
- <div className="header-stat">
466
- <span>🌿</span>
467
- <div>
468
- <div>{Math.round(userStats.carbonSaved)}</div>
469
- <div>COβ‚‚ Saved (kg)</div>
470
- </div>
471
- </div>
472
- <div className="header-stat">
473
- <span>πŸ’§</span>
474
- <div>
475
- <div>{userStats.waterTests}</div>
476
- <div>Water Tests</div>
477
- </div>
478
- </div>
479
- <div className="header-stat">
480
- <span>🦜</span>
481
- <div>
482
- <div>{userStats.biodiversityScans}</div>
483
- <div>Bio Scans</div>
484
- </div>
485
- </div>
486
- <div className="header-stat">
487
- <span>🌳</span>
488
- <div>
489
- <div>{userStats.treesPlanted}</div>
490
- <div>Trees Planted</div>
491
- </div>
492
- </div>
493
- </div>
494
-
495
- </div>
496
- </div>
497
-
498
- {/* Content */}
499
- <div className="terra-content">
500
- <CurrentComponent
501
- onNavigate={handlePageChange}
502
- onActivityComplete={handleActivityComplete}
503
- onAuthChange={handleAuthChange}
504
- userStats={userStats}
505
- currentUser={currentUser}
506
- isAuthenticated={currentUser && !currentUser.isGuest}
507
- />
508
- </div>
509
- </div>
510
- </div>
511
- );
512
- }
513
-
514
  export default App;
 
1
+ import React, { useState, useEffect } from 'react';
2
+ import './App.css';
3
+ import { systemInitializer } from './utils/systemInitializer.js';
4
+ import { authManager } from './utils/auth.js';
5
+ import LoadingScreen from './components/LoadingScreen';
6
+
7
+ // Import all your pages
8
+ import Dashboard from './pages/Dashboard';
9
+ import AquaLens from './pages/AquaLens';
10
+ import BiodiversityEar from './pages/BiodiversityEar';
11
+ import CarbonOptimizer from './pages/CarbonOptimizer';
12
+ import SmartFarming from './pages/SmartFarming';
13
+ import EWasteRecycling from './pages/EWasteRecycling';
14
+ import AirQuality from './pages/AirQuality';
15
+ import FloraShield from './pages/FloraShield';
16
+ import FoodWasteReduction from './pages/FoodWasteReduction';
17
+ import EnvironmentalJustice from './pages/EnvironmentalJustice';
18
+ import EcoSonification from './pages/EcoSonification';
19
+ import PhantomFootprint from './pages/PhantomFootprint';
20
+ import UpcyclingAgent from './pages/UpcyclingAgent';
21
+ import PackagingDesigner from './pages/PackagingDesigner';
22
+ import Impact from './pages/Impact';
23
+ import EcoTasks from './pages/EcoTasks';
24
+ import Learn from './pages/Learn';
25
+ import Startups from './pages/Startups';
26
+ import Community from './pages/Community';
27
+ import Profile from './pages/Profile';
28
+ import Login from './pages/Login';
29
+ import DigitalQuarry from './pages/DigitalQuarry';
30
+ import BioStreamAI from './pages/BioStreamAI';
31
+ import EWasteProspector from './pages/EWasteProspector';
32
+ import GeneticResilience from './pages/GeneticResilience';
33
+
34
+ function App() {
35
+ const [activePage, setActivePage] = useState('Dashboard');
36
+ const [userStats, setUserStats] = useState({
37
+ carbonSaved: 0,
38
+ waterTests: 0,
39
+ biodiversityScans: 0,
40
+ treesPlanted: 0,
41
+ wasteReduced: 0,
42
+ energySaved: 0
43
+ });
44
+ const [currentUser, setCurrentUser] = useState(null);
45
+ const [systemReady, setSystemReady] = useState(false);
46
+ const [systemStatus, setSystemStatus] = useState(null);
47
+ const [isLoading, setIsLoading] = useState(true);
48
+
49
+ // Initialize advanced systems and authentication on app start
50
+ useEffect(() => {
51
+ const initializeSystems = async () => {
52
+ console.log('πŸš€ GreenPlus by GXS: Initializing Advanced Environmental Systems...');
53
+
54
+ try {
55
+ const status = await systemInitializer.initialize();
56
+ setSystemStatus(status);
57
+ setSystemReady(status.overallReady);
58
+
59
+ // Initialize authentication
60
+ const user = authManager.getCurrentUser();
61
+ setCurrentUser(user);
62
+
63
+ if (status.overallReady) {
64
+ console.log('βœ… GreenPlus by GXS: All systems operational!');
65
+ } else {
66
+ console.warn('⚠️ GreenPlus by GXS: Running with limited functionality');
67
+ }
68
+ } catch (error) {
69
+ console.error('❌ GreenPlus by GXS: System initialization failed:', error);
70
+ setSystemReady(false);
71
+ }
72
+ };
73
+
74
+ initializeSystems();
75
+
76
+ // Show loading screen for 2.5 seconds
77
+ const loadingTimer = setTimeout(() => {
78
+ setIsLoading(false);
79
+ }, 2500);
80
+
81
+ return () => clearTimeout(loadingTimer);
82
+ }, []);
83
+
84
+ // Handle authentication changes
85
+ const handleAuthChange = (user) => {
86
+ setCurrentUser(user);
87
+ updateUserStats();
88
+ };
89
+
90
+ // Update user stats from auth manager
91
+ const updateUserStats = () => {
92
+ const stats = authManager.getUserStats();
93
+
94
+ // Only show demo stats for actual guest users, not logged-in users
95
+ const isGuest = currentUser?.isGuest === true;
96
+ const isNewGuest = isGuest && !stats.carbonSaved && !stats.waterTests && !stats.biodiversityScans;
97
+
98
+ console.log('πŸ”„ App.js updateUserStats called');
99
+ console.log('πŸ“Š Raw stats from authManager:', stats);
100
+ console.log('πŸ‘€ Current user:', currentUser);
101
+ console.log('πŸ†• Is new guest:', isNewGuest);
102
+
103
+ const newStats = {
104
+ carbonSaved: stats.carbonSaved || (isNewGuest ? 12 : 0),
105
+ waterTests: stats.waterTests || (isNewGuest ? 3 : 0),
106
+ biodiversityScans: stats.biodiversityScans || (isNewGuest ? 2 : 0),
107
+ treesPlanted: stats.treesPlanted || 0,
108
+ wasteReduced: stats.wasteReduced || 0,
109
+ energySaved: stats.energySaved || 0
110
+ };
111
+
112
+ console.log('πŸ“ˆ Setting userStats to:', newStats);
113
+ setUserStats(newStats);
114
+ };
115
+
116
+ // Set up periodic stats refresh
117
+ useEffect(() => {
118
+ // Initial stats load
119
+ updateUserStats();
120
+
121
+ // Refresh stats every 10 seconds (less frequent to reduce flickering)
122
+ const statsInterval = setInterval(updateUserStats, 10000);
123
+
124
+ return () => clearInterval(statsInterval);
125
+ }, [currentUser]);
126
+
127
+ const pages = [
128
+ {
129
+ id: 'Dashboard',
130
+ name: 'Dashboard',
131
+ icon: '🏠',
132
+ component: Dashboard,
133
+ description: 'Overview & Analytics'
134
+ },
135
+ {
136
+ id: 'AquaLens',
137
+ name: 'AquaLens',
138
+ icon: 'πŸ’§',
139
+ component: AquaLens,
140
+ description: 'Water Quality Analysis'
141
+ },
142
+ {
143
+ id: 'BiodiversityEar',
144
+ name: 'BiodiversityEar',
145
+ icon: '🦜',
146
+ component: BiodiversityEar,
147
+ description: 'Ecosystem Monitoring'
148
+ },
149
+ {
150
+ id: 'CarbonOptimizer',
151
+ name: 'Carbon Optimizer',
152
+ icon: '🌱',
153
+ component: CarbonOptimizer,
154
+ description: 'Carbon Footprint Tracking'
155
+ },
156
+ {
157
+ id: 'SmartFarming',
158
+ name: 'Smart Farming',
159
+ icon: '🌾',
160
+ component: SmartFarming,
161
+ description: 'Agricultural Intelligence'
162
+ },
163
+ {
164
+ id: 'EWasteRecycling',
165
+ name: 'E-Waste Recycling',
166
+ icon: '♻️',
167
+ component: EWasteRecycling,
168
+ description: 'Electronic Waste Management'
169
+ },
170
+ {
171
+ id: 'AirQuality',
172
+ name: 'Air Quality',
173
+ icon: '🌬️',
174
+ component: AirQuality,
175
+ description: 'Air Pollution Monitoring'
176
+ },
177
+ {
178
+ id: 'FloraShield',
179
+ name: 'FloraShield',
180
+ icon: 'πŸ›‘οΈ',
181
+ component: FloraShield,
182
+ description: 'Plant Disease Detection'
183
+ },
184
+ {
185
+ id: 'FoodWasteReduction',
186
+ name: 'Food Waste Reduction',
187
+ icon: '🍎',
188
+ component: FoodWasteReduction,
189
+ description: 'Food Rescue Network'
190
+ },
191
+ {
192
+ id: 'EnvironmentalJustice',
193
+ name: 'Environmental Justice',
194
+ icon: 'βš–οΈ',
195
+ component: EnvironmentalJustice,
196
+ description: 'Equity & Justice'
197
+ },
198
+ {
199
+ id: 'EcoSonification',
200
+ name: 'EcoSonification',
201
+ icon: '🎡',
202
+ component: EcoSonification,
203
+ description: 'Environmental Sound Art'
204
+ },
205
+ {
206
+ id: 'PhantomFootprint',
207
+ name: 'Phantom Footprint',
208
+ icon: 'πŸ‘»',
209
+ component: PhantomFootprint,
210
+ description: 'Hidden Impact Tracker'
211
+ },
212
+ {
213
+ id: 'UpcyclingAgent',
214
+ name: 'Upcycling Agent',
215
+ icon: 'πŸ”„',
216
+ component: UpcyclingAgent,
217
+ description: 'Creative Reuse Assistant'
218
+ },
219
+ {
220
+ id: 'PackagingDesigner',
221
+ name: 'Packaging Designer',
222
+ icon: 'πŸ“¦',
223
+ component: PackagingDesigner,
224
+ description: 'Sustainable Packaging'
225
+ },
226
+ {
227
+ id: 'DigitalQuarry',
228
+ name: 'Digital Quarry',
229
+ icon: 'πŸ—οΈ',
230
+ component: DigitalQuarry,
231
+ description: 'Construction Waste Marketplace'
232
+ },
233
+ {
234
+ id: 'BioStreamAI',
235
+ name: 'Bio-Stream AI',
236
+ icon: '🧬',
237
+ component: BioStreamAI,
238
+ description: 'Environmental DNA Analysis'
239
+ },
240
+ {
241
+ id: 'EWasteProspector',
242
+ name: 'E-Waste Prospector',
243
+ icon: '⚑',
244
+ component: EWasteProspector,
245
+ description: 'Critical Mineral Recovery'
246
+ },
247
+ {
248
+ id: 'GeneticResilience',
249
+ name: 'Genetic Resilience',
250
+ icon: '🌾',
251
+ component: GeneticResilience,
252
+ description: 'Climate Crop Analysis'
253
+ },
254
+ {
255
+ id: 'Impact',
256
+ name: 'Global Impact',
257
+ icon: '🌍',
258
+ component: Impact,
259
+ description: 'Environmental Impact Data'
260
+ },
261
+ {
262
+ id: 'EcoTasks',
263
+ name: 'Eco Tasks',
264
+ icon: 'βœ…',
265
+ component: EcoTasks,
266
+ description: 'Daily Green Actions'
267
+ },
268
+ {
269
+ id: 'Learn',
270
+ name: 'Learn',
271
+ icon: 'πŸ“š',
272
+ component: Learn,
273
+ description: 'Environmental Education'
274
+ },
275
+ {
276
+ id: 'Startups',
277
+ name: 'Green Startups',
278
+ icon: 'πŸš€',
279
+ component: Startups,
280
+ description: 'Sustainable Innovation'
281
+ },
282
+ {
283
+ id: 'Community',
284
+ name: 'Community',
285
+ icon: 'πŸ‘₯',
286
+ component: Community,
287
+ description: 'Connect with eco champions'
288
+ },
289
+ {
290
+ id: 'Profile',
291
+ name: 'My Profile',
292
+ icon: 'πŸ‘€',
293
+ component: Profile,
294
+ description: 'View your environmental impact'
295
+ },
296
+ {
297
+ id: 'Login',
298
+ name: 'Login',
299
+ icon: 'πŸ”‘',
300
+ component: Login,
301
+ description: 'Sign in or create account'
302
+ }
303
+ ];
304
+
305
+ // Initialize page from URL on app load
306
+ useEffect(() => {
307
+ const urlParams = new URLSearchParams(window.location.search);
308
+ const pageFromUrl = urlParams.get('page');
309
+
310
+ if (pageFromUrl && pages.some(page => page.id === pageFromUrl)) {
311
+ setActivePage(pageFromUrl);
312
+ } else {
313
+ // If no valid page in URL, set default and update URL
314
+ const defaultPage = 'Dashboard';
315
+ setActivePage(defaultPage);
316
+ updateURL(defaultPage);
317
+ }
318
+ }, []);
319
+
320
+ // Function to update URL without page reload
321
+ const updateURL = (pageId) => {
322
+ const newUrl = `${window.location.pathname}?page=${pageId}`;
323
+ window.history.pushState({ page: pageId }, '', newUrl);
324
+ };
325
+
326
+ // Handle browser back/forward buttons
327
+ useEffect(() => {
328
+ const handlePopState = (event) => {
329
+ const urlParams = new URLSearchParams(window.location.search);
330
+ const pageFromUrl = urlParams.get('page') || 'Dashboard';
331
+
332
+ if (pages.some(page => page.id === pageFromUrl)) {
333
+ setActivePage(pageFromUrl);
334
+ }
335
+ };
336
+
337
+ window.addEventListener('popstate', handlePopState);
338
+ return () => window.removeEventListener('popstate', handlePopState);
339
+ }, []);
340
+
341
+ const currentPage = pages.find(page => page.id === activePage);
342
+ const CurrentComponent = currentPage?.component || Dashboard;
343
+
344
+ const handlePageChange = (pageId) => {
345
+ setActivePage(pageId);
346
+ updateURL(pageId);
347
+ };
348
+
349
+ // Handle activity completion to update stats immediately
350
+ const handleActivityComplete = async (activity) => {
351
+ console.log('🎯 App.js handleActivityComplete called with:', activity);
352
+
353
+ // Log activity through auth manager if activity data is provided
354
+ if (activity && activity.type) {
355
+ console.log('πŸ“ Logging activity through authManager...');
356
+ await authManager.logActivity(activity.description || 'Environmental action', {
357
+ type: activity.type,
358
+ amount: activity.amount,
359
+ points: activity.points || 10
360
+ });
361
+ console.log('βœ… Activity logged successfully');
362
+ }
363
+
364
+ // Update stats display
365
+ console.log('πŸ”„ Calling updateUserStats after activity completion...');
366
+ updateUserStats();
367
+ };
368
+
369
+ // Show loading screen first
370
+ if (isLoading) {
371
+ return <LoadingScreen />;
372
+ }
373
+
374
+ return (
375
+ <div className="terra-app">
376
+ {/* Sidebar */}
377
+ <div className="terra-sidebar open">
378
+ {/* Logo */}
379
+ <div className="terra-logo">
380
+ <div className="logo-container">
381
+ <div className="logo-icon">🌿</div>
382
+ <div className="logo-text">
383
+ <h1>EcoSpire</h1>
384
+ <p>Environmental Intelligence Hub</p>
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ {/* Navigation */}
390
+ <div className="terra-nav">
391
+ {pages.map(page => (
392
+ <div
393
+ key={page.id}
394
+ className={`nav-item ${activePage === page.id ? 'active' : ''}`}
395
+ onClick={() => handlePageChange(page.id)}
396
+ >
397
+ <span className="nav-icon">{page.icon}</span>
398
+ <div className="nav-content">
399
+ <span className="nav-name">{page.name}</span>
400
+ <span className="nav-desc">{page.description}</span>
401
+ </div>
402
+ </div>
403
+ ))}
404
+ </div>
405
+
406
+
407
+ </div>
408
+
409
+ {/* Main Content */}
410
+ <div className="terra-main">
411
+ {/* Header */}
412
+ <div className="terra-header">
413
+ <div className="header-left">
414
+ <h1 className="page-title">
415
+ <span className="title-icon">{currentPage?.icon}</span>
416
+ {currentPage?.name}
417
+ </h1>
418
+ <p className="page-subtitle">{currentPage?.description}</p>
419
+ </div>
420
+ <div className="header-right">
421
+ {/* User Info */}
422
+ {currentUser && (
423
+ <div style={{
424
+ display: 'flex',
425
+ alignItems: 'center',
426
+ gap: '15px',
427
+ marginRight: '20px'
428
+ }}>
429
+ <div
430
+ onClick={() => handlePageChange('Profile')}
431
+ style={{
432
+ display: 'flex',
433
+ alignItems: 'center',
434
+ gap: '8px',
435
+ background: 'rgba(255,255,255,0.1)',
436
+ padding: '8px 15px',
437
+ borderRadius: '20px',
438
+ cursor: 'pointer',
439
+ transition: 'background 0.2s'
440
+ }}
441
+ onMouseEnter={(e) => e.target.style.background = 'rgba(255,255,255,0.2)'}
442
+ onMouseLeave={(e) => e.target.style.background = 'rgba(255,255,255,0.1)'}
443
+ title="Click to view profile"
444
+ >
445
+ <span style={{ fontSize: '1.2rem' }}>{currentUser.avatar}</span>
446
+ <span style={{ color: 'white', fontWeight: 'bold' }}>
447
+ {currentUser.name}
448
+ </span>
449
+ {currentUser.isGuest && (
450
+ <span style={{
451
+ background: '#FF9800',
452
+ color: 'white',
453
+ padding: '2px 8px',
454
+ borderRadius: '10px',
455
+ fontSize: '0.7rem'
456
+ }}>
457
+ GUEST
458
+ </span>
459
+ )}
460
+ </div>
461
+ </div>
462
+ )}
463
+
464
+ <div className="header-stats">
465
+ <div className="header-stat">
466
+ <span>🌿</span>
467
+ <div>
468
+ <div>{Math.round(userStats.carbonSaved)}</div>
469
+ <div>COβ‚‚ Saved (kg)</div>
470
+ </div>
471
+ </div>
472
+ <div className="header-stat">
473
+ <span>πŸ’§</span>
474
+ <div>
475
+ <div>{userStats.waterTests}</div>
476
+ <div>Water Tests</div>
477
+ </div>
478
+ </div>
479
+ <div className="header-stat">
480
+ <span>🦜</span>
481
+ <div>
482
+ <div>{userStats.biodiversityScans}</div>
483
+ <div>Bio Scans</div>
484
+ </div>
485
+ </div>
486
+ <div className="header-stat">
487
+ <span>🌳</span>
488
+ <div>
489
+ <div>{userStats.treesPlanted}</div>
490
+ <div>Trees Planted</div>
491
+ </div>
492
+ </div>
493
+ </div>
494
+
495
+ </div>
496
+ </div>
497
+
498
+ {/* Content */}
499
+ <div className="terra-content">
500
+ <CurrentComponent
501
+ onNavigate={handlePageChange}
502
+ onActivityComplete={handleActivityComplete}
503
+ onAuthChange={handleAuthChange}
504
+ userStats={userStats}
505
+ currentUser={currentUser}
506
+ isAuthenticated={currentUser && !currentUser.isGuest}
507
+ />
508
+ </div>
509
+ </div>
510
+ </div>
511
+ );
512
+ }
513
+
514
  export default App;