gaialive commited on
Commit
a47f71c
·
verified ·
1 Parent(s): 585aa58

Upload Community.js

Browse files
Files changed (1) hide show
  1. web/src/pages/Community.js +1265 -0
web/src/pages/Community.js ADDED
@@ -0,0 +1,1265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { authManager } from '../utils/auth';
3
+ import { imageHandler } from '../utils/imageHandler';
4
+
5
+ const Community = ({ onNavigate }) => {
6
+ const [posts, setPosts] = useState([]);
7
+ const [newPost, setNewPost] = useState('');
8
+ const [currentUser, setCurrentUser] = useState(null);
9
+ const [activeTab, setActiveTab] = useState('feed');
10
+ const [leaderboard, setLeaderboard] = useState([]);
11
+ const [communityStats, setCommunityStats] = useState({});
12
+ const [isLoading, setIsLoading] = useState(false);
13
+ const [selectedImage, setSelectedImage] = useState(null);
14
+ const [selectedLocation, setSelectedLocation] = useState('');
15
+ const [postType, setPostType] = useState('general');
16
+ const fileInputRef = useRef(null);
17
+
18
+ useEffect(() => {
19
+ loadCommunityData();
20
+ const user = authManager.getCurrentUser();
21
+ setCurrentUser(user);
22
+ }, []);
23
+
24
+ const loadCommunityData = () => {
25
+ // Load community posts from localStorage or generate demo data
26
+ const savedPosts = localStorage.getItem('ecospire_community_posts');
27
+ if (savedPosts) {
28
+ setPosts(JSON.parse(savedPosts));
29
+ } else {
30
+ generateInitialPosts();
31
+ }
32
+
33
+ // Load leaderboard
34
+ setLeaderboard(authManager.getLeaderboard());
35
+
36
+ // Generate community stats
37
+ setCommunityStats({
38
+ totalMembers: 12847 + Math.floor(Math.random() * 100),
39
+ waterTests: 45231 + Math.floor(Math.random() * 50),
40
+ speciesIdentified: 28956 + Math.floor(Math.random() * 20),
41
+ co2Saved: 156789 + Math.floor(Math.random() * 100),
42
+ activeToday: 1247 + Math.floor(Math.random() * 50),
43
+ postsToday: 89 + Math.floor(Math.random() * 10)
44
+ });
45
+ };
46
+
47
+ const generateInitialPosts = () => {
48
+ const initialPosts = [
49
+ {
50
+ id: 1,
51
+ author: 'EcoExplorer',
52
+ avatar: '🌱',
53
+ timestamp: Date.now() - 2 * 60 * 60 * 1000, // 2 hours ago
54
+ content: 'Just completed my first water quality test using AquaLens! The results were fascinating - found some concerning nitrate levels in our local stream. Time to take action! 💧',
55
+ likes: 12,
56
+ comments: [
57
+ { author: 'WaterGuardian', content: 'Great work! Have you contacted local authorities about the nitrate levels?', timestamp: Date.now() - 1 * 60 * 60 * 1000 },
58
+ { author: 'EcoNewbie', content: 'How accurate is AquaLens? Thinking of trying it myself!', timestamp: Date.now() - 30 * 60 * 1000 }
59
+ ],
60
+ type: 'water_test',
61
+ location: 'Riverside Park Stream',
62
+ image: {
63
+ url: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgZmlsbD0iIzg3Q0VFQiIvPjx0ZXh0IHg9IjIwMCIgeT0iMTUwIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iMTgiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7wn5KnIFdhdGVyIFRlc3QgU3RyaXA8L3RleHQ+PC9zdmc+',
64
+ name: 'water_test_strip.jpg',
65
+ size: 245760
66
+ },
67
+ data: { ph: 7.2, nitrates: 15, chlorine: 2.1 }
68
+ },
69
+ {
70
+ id: 2,
71
+ author: 'BirdWatcher92',
72
+ avatar: '🦜',
73
+ timestamp: Date.now() - 4 * 60 * 60 * 1000, // 4 hours ago
74
+ content: 'BiodiversityEar identified 15 different bird species in my morning recording! Including a rare warbler that hasn\'t been spotted in our area for years. Nature is amazing! 🎵',
75
+ likes: 24,
76
+ comments: [
77
+ { author: 'NatureExpert', content: 'Which warbler species? That\'s incredible!', timestamp: Date.now() - 2 * 60 * 60 * 1000 },
78
+ { author: 'BioStudent', content: 'Can you share the recording? Would love to hear it!', timestamp: Date.now() - 1 * 60 * 60 * 1000 }
79
+ ],
80
+ type: 'biodiversity_scan',
81
+ location: 'Central City Park',
82
+ image: {
83
+ url: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9InNreSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiM4N0NFRUIiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0eWxlPSJzdG9wLWNvbG9yOiM5OERCOEMiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgZmlsbD0idXJsKCNza3kpIi8+PGNpcmNsZSBjeD0iMzIwIiBjeT0iNjAiIHI9IjMwIiBmaWxsPSIjRkZENzAwIi8+PHJlY3QgeD0iMCIgeT0iMjAwIiB3aWR0aD0iNDAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iIzIyOEIyMiIvPjx0ZXh0IHg9IjIwMCIgeT0iMTUwIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iMTYiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj7wn6acIEJpcmQgV2F0Y2hpbmcgU3BvdDwvdGV4dD48L3N2Zz4=',
84
+ name: 'bird_watching_spot.jpg',
85
+ size: 189440
86
+ },
87
+ data: { speciesCount: 15, rareSpecies: 'Yellow Warbler' }
88
+ },
89
+ {
90
+ id: 3,
91
+ author: 'GreenThumb',
92
+ avatar: '🌿',
93
+ timestamp: Date.now() - 24 * 60 * 60 * 1000, // 1 day ago
94
+ content: 'FloraShield helped me identify an invasive plant species in my garden before it could spread. Early detection is key to protecting our local ecosystem! 🛡️',
95
+ likes: 18,
96
+ comments: [
97
+ { author: 'GardenExpert', content: 'Which species was it? Always good to share for others to watch out for!', timestamp: Date.now() - 20 * 60 * 60 * 1000 }
98
+ ],
99
+ type: 'plant_identification',
100
+ location: 'Home Garden',
101
+ image: {
102
+ url: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgZmlsbD0iIzIyOEIyMiIvPjxwYXRoIGQ9Ik0xMDAsMjUwIEwxNTAsMTUwIEwyMDAsMjAwIEwyNTAsMTAwIEwzMDAsMTgwIiBzdHJva2U9IiM5OERCOEMiIHN0cm9rZS13aWR0aD0iOCIgZmlsbD0ibm9uZSIvPjxjaXJjbGUgY3g9IjE1MCIgY3k9IjE1MCIgcj0iMTUiIGZpbGw9IiNGRkQ3MDAiLz48Y2lyY2xlIGN4PSIyNTAiIGN5PSIxMDAiIHI9IjEyIiBmaWxsPSIjRkY2MzQ3Ii8+PHRleHQgeD0iMjAwIiB5PSIyODAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPvCfjL8gSW52YXNpdmUgUGxhbnQgRGV0ZWN0ZWQ8L3RleHQ+PC9zdmc+',
103
+ name: 'invasive_plant.jpg',
104
+ size: 156780
105
+ },
106
+ data: { species: 'Japanese Knotweed', confidence: 92 }
107
+ },
108
+ {
109
+ id: 4,
110
+ author: 'CarbonCrusher',
111
+ avatar: '🌳',
112
+ timestamp: Date.now() - 6 * 60 * 60 * 1000, // 6 hours ago
113
+ content: 'Completed my monthly carbon footprint analysis. Managed to reduce my emissions by 23% this month through better transport choices and energy efficiency! 🚲⚡',
114
+ likes: 31,
115
+ comments: [
116
+ { author: 'EcoCommuter', content: 'Amazing! What transport changes did you make?', timestamp: Date.now() - 3 * 60 * 60 * 1000 }
117
+ ],
118
+ type: 'carbon_reduction',
119
+ data: { reduction: 23, co2Saved: 45 }
120
+ }
121
+ ];
122
+
123
+ setPosts(initialPosts);
124
+ localStorage.setItem('ecospire_community_posts', JSON.stringify(initialPosts));
125
+ };
126
+
127
+ const handleImageSelect = async (e) => {
128
+ const file = e.target.files[0];
129
+ if (!file) return;
130
+
131
+ try {
132
+ setIsLoading(true);
133
+ const processedImage = await imageHandler.processImage(file, {
134
+ compress: true,
135
+ maxWidth: 800,
136
+ quality: 0.8
137
+ });
138
+
139
+ setSelectedImage({
140
+ file: file,
141
+ preview: processedImage.preview,
142
+ name: processedImage.original.name,
143
+ size: processedImage.processed.size,
144
+ processedData: processedImage
145
+ });
146
+ } catch (error) {
147
+ alert(`Image processing failed: ${error.message}`);
148
+ console.error('Image processing error:', error);
149
+ } finally {
150
+ setIsLoading(false);
151
+ }
152
+ };
153
+
154
+ const removeImage = () => {
155
+ setSelectedImage(null);
156
+ if (fileInputRef.current) {
157
+ fileInputRef.current.value = '';
158
+ }
159
+ };
160
+
161
+ const getCurrentLocation = () => {
162
+ if (navigator.geolocation) {
163
+ navigator.geolocation.getCurrentPosition(
164
+ (position) => {
165
+ const { latitude, longitude } = position.coords;
166
+ // Simulate reverse geocoding
167
+ const locations = [
168
+ 'Central Park, New York',
169
+ 'Golden Gate Park, San Francisco',
170
+ 'Hyde Park, London',
171
+ 'Vondelpark, Amsterdam',
172
+ 'Retiro Park, Madrid'
173
+ ];
174
+ const randomLocation = locations[Math.floor(Math.random() * locations.length)];
175
+ setSelectedLocation(randomLocation);
176
+ },
177
+ (error) => {
178
+ console.error('Geolocation error:', error);
179
+ setSelectedLocation('Location unavailable');
180
+ }
181
+ );
182
+ } else {
183
+ setSelectedLocation('Geolocation not supported');
184
+ }
185
+ };
186
+
187
+ const handlePostSubmit = async (e) => {
188
+ e.preventDefault();
189
+ if (!newPost.trim()) return;
190
+
191
+ if (!currentUser || currentUser.isGuest) {
192
+ alert('Please create an account to post in the community!');
193
+ onNavigate && onNavigate('Login');
194
+ return;
195
+ }
196
+
197
+ setIsLoading(true);
198
+
199
+ // Process and store image
200
+ let imageData = null;
201
+ if (selectedImage) {
202
+ const imageId = `post_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
203
+
204
+ // Store image using imageHandler
205
+ const stored = imageHandler.storeImage(selectedImage.processedData, imageId);
206
+
207
+ if (stored) {
208
+ imageData = {
209
+ id: imageId,
210
+ url: selectedImage.preview,
211
+ name: selectedImage.name,
212
+ size: selectedImage.size,
213
+ type: selectedImage.file.type
214
+ };
215
+ } else {
216
+ // Fallback to direct preview if storage fails
217
+ imageData = {
218
+ url: selectedImage.preview,
219
+ name: selectedImage.name,
220
+ size: selectedImage.size,
221
+ type: selectedImage.file.type
222
+ };
223
+ }
224
+ }
225
+
226
+ const post = {
227
+ id: Date.now(),
228
+ author: currentUser.name,
229
+ avatar: currentUser.avatar,
230
+ timestamp: Date.now(),
231
+ content: newPost,
232
+ likes: 0,
233
+ comments: [],
234
+ type: postType,
235
+ location: selectedLocation || null,
236
+ image: imageData,
237
+ data: generatePostData(postType)
238
+ };
239
+
240
+ const updatedPosts = [post, ...posts];
241
+ setPosts(updatedPosts);
242
+ localStorage.setItem('ecospire_community_posts', JSON.stringify(updatedPosts));
243
+
244
+ // Log activity with enhanced points for media posts
245
+ const points = selectedImage ? 25 : 15;
246
+ await authManager.logActivity('Posted in community', {
247
+ type: 'community_post',
248
+ content: newPost.substring(0, 50) + '...',
249
+ hasImage: !!selectedImage,
250
+ postType: postType,
251
+ points: points
252
+ });
253
+
254
+ // Reset form
255
+ setNewPost('');
256
+ setSelectedImage(null);
257
+ setSelectedLocation('');
258
+ setPostType('general');
259
+ if (fileInputRef.current) {
260
+ fileInputRef.current.value = '';
261
+ }
262
+
263
+ setIsLoading(false);
264
+ };
265
+
266
+ const generatePostData = (type) => {
267
+ switch (type) {
268
+ case 'water_test':
269
+ return {
270
+ ph: (6.5 + Math.random() * 2).toFixed(1),
271
+ nitrates: Math.floor(Math.random() * 20),
272
+ chlorine: (Math.random() * 3).toFixed(1)
273
+ };
274
+ case 'biodiversity_scan':
275
+ return {
276
+ speciesCount: Math.floor(Math.random() * 20) + 5,
277
+ rareSpecies: ['Rare Warbler', 'Endangered Butterfly'][Math.floor(Math.random() * 2)]
278
+ };
279
+ case 'carbon_reduction':
280
+ return {
281
+ co2Saved: Math.floor(Math.random() * 50) + 10,
282
+ reduction: Math.floor(Math.random() * 30) + 10
283
+ };
284
+ case 'plant_identification':
285
+ return {
286
+ species: 'Unknown Plant Species',
287
+ confidence: Math.floor(Math.random() * 30) + 70
288
+ };
289
+ default:
290
+ return {};
291
+ }
292
+ };
293
+
294
+ const handleLike = async (postId) => {
295
+ if (!currentUser || currentUser.isGuest) {
296
+ alert('Please create an account to interact with posts!');
297
+ return;
298
+ }
299
+
300
+ const updatedPosts = posts.map(post => {
301
+ if (post.id === postId) {
302
+ return { ...post, likes: post.likes + 1 };
303
+ }
304
+ return post;
305
+ });
306
+
307
+ setPosts(updatedPosts);
308
+ localStorage.setItem('ecospire_community_posts', JSON.stringify(updatedPosts));
309
+
310
+ // Log activity
311
+ await authManager.logActivity('Liked community post', {
312
+ type: 'community_interaction',
313
+ action: 'like',
314
+ points: 2
315
+ });
316
+ };
317
+
318
+ const handleComment = async (postId, comment) => {
319
+ if (!currentUser || currentUser.isGuest) {
320
+ alert('Please create an account to comment!');
321
+ return;
322
+ }
323
+
324
+ if (!comment.trim()) return;
325
+
326
+ const newComment = {
327
+ author: currentUser.name,
328
+ content: comment,
329
+ timestamp: Date.now()
330
+ };
331
+
332
+ const updatedPosts = posts.map(post => {
333
+ if (post.id === postId) {
334
+ return { ...post, comments: [...post.comments, newComment] };
335
+ }
336
+ return post;
337
+ });
338
+
339
+ setPosts(updatedPosts);
340
+ localStorage.setItem('ecospire_community_posts', JSON.stringify(updatedPosts));
341
+
342
+ // Log activity
343
+ await authManager.logActivity('Commented on post', {
344
+ type: 'community_interaction',
345
+ action: 'comment',
346
+ points: 5
347
+ });
348
+ };
349
+
350
+ const formatTimeAgo = (timestamp) => {
351
+ const now = Date.now();
352
+ const diff = now - timestamp;
353
+ const minutes = Math.floor(diff / (1000 * 60));
354
+ const hours = Math.floor(diff / (1000 * 60 * 60));
355
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
356
+
357
+ if (minutes < 60) return `${minutes} minutes ago`;
358
+ if (hours < 24) return `${hours} hours ago`;
359
+ return `${days} days ago`;
360
+ };
361
+
362
+ const getPostTypeIcon = (type) => {
363
+ const icons = {
364
+ water_test: '💧',
365
+ biodiversity_scan: '🦜',
366
+ plant_identification: '🌿',
367
+ carbon_reduction: '🌳',
368
+ general: '💬'
369
+ };
370
+ return icons[type] || '💬';
371
+ };
372
+
373
+ return (
374
+ <div className="community-page" style={{ padding: '20px', maxWidth: '1200px', margin: '0 auto' }}>
375
+ {/* Header */}
376
+ <div style={{
377
+ background: 'linear-gradient(135deg, #3498db 0%, #2980b9 100%)',
378
+ borderRadius: '12px',
379
+ padding: '30px',
380
+ color: 'white',
381
+ marginBottom: '30px',
382
+ textAlign: 'center'
383
+ }}>
384
+ <h1 style={{ margin: '0 0 10px 0', fontSize: '2.5rem' }}>👥 GreenPlus by GXS Community</h1>
385
+ <p style={{ margin: '0 0 20px 0', fontSize: '1.1rem', opacity: 0.9 }}>
386
+ Connect with environmental champions worldwide
387
+ </p>
388
+
389
+ {/* User Status */}
390
+ {currentUser && (
391
+ <div style={{
392
+ background: 'rgba(255,255,255,0.2)',
393
+ borderRadius: '8px',
394
+ padding: '15px',
395
+ display: 'inline-block'
396
+ }}>
397
+ <span style={{ fontSize: '1.5rem', marginRight: '10px' }}>{currentUser.avatar}</span>
398
+ <span style={{ fontSize: '1.1rem', fontWeight: 'bold' }}>
399
+ Welcome, {currentUser.name}!
400
+ </span>
401
+ {currentUser.isGuest && (
402
+ <span style={{ fontSize: '0.9rem', opacity: 0.8, marginLeft: '10px' }}>
403
+ (Guest Mode - <button
404
+ onClick={() => onNavigate && onNavigate('Login')}
405
+ style={{ background: 'none', border: 'none', color: 'white', textDecoration: 'underline', cursor: 'pointer' }}
406
+ >
407
+ Create Account
408
+ </button>)
409
+ </span>
410
+ )}
411
+ </div>
412
+ )}
413
+ </div>
414
+
415
+ {/* Navigation Tabs */}
416
+ <div style={{
417
+ display: 'flex',
418
+ gap: '10px',
419
+ marginBottom: '30px',
420
+ justifyContent: 'center'
421
+ }}>
422
+ {[
423
+ { id: 'feed', name: 'Community Feed', icon: '📱' },
424
+ { id: 'leaderboard', name: 'Leaderboard', icon: '🏆' },
425
+ { id: 'stats', name: 'Community Stats', icon: '📊' }
426
+ ].map(tab => (
427
+ <button
428
+ key={tab.id}
429
+ onClick={() => setActiveTab(tab.id)}
430
+ style={{
431
+ padding: '12px 24px',
432
+ borderRadius: '25px',
433
+ border: 'none',
434
+ background: activeTab === tab.id ? '#3498db' : '#ecf0f1',
435
+ color: activeTab === tab.id ? 'white' : '#2c3e50',
436
+ cursor: 'pointer',
437
+ fontWeight: '600',
438
+ fontSize: '14px',
439
+ display: 'flex',
440
+ alignItems: 'center',
441
+ gap: '8px'
442
+ }}
443
+ >
444
+ <span>{tab.icon}</span>
445
+ {tab.name}
446
+ </button>
447
+ ))}
448
+ </div>
449
+
450
+ {/* Community Feed Tab */}
451
+ {activeTab === 'feed' && (
452
+ <>
453
+ {/* Create Post */}
454
+ <div style={{
455
+ background: 'white',
456
+ borderRadius: '12px',
457
+ padding: '20px',
458
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
459
+ marginBottom: '30px'
460
+ }}>
461
+ <h3 style={{ margin: '0 0 15px 0', color: '#2c3e50' }}>Share Your Environmental Impact</h3>
462
+
463
+ {/* Post Type Selector */}
464
+ <div style={{ marginBottom: '15px' }}>
465
+ <label style={{ display: 'block', marginBottom: '8px', fontWeight: '500', color: '#2c3e50' }}>
466
+ Post Type:
467
+ </label>
468
+ <select
469
+ value={postType}
470
+ onChange={(e) => setPostType(e.target.value)}
471
+ disabled={!currentUser || currentUser.isGuest}
472
+ style={{
473
+ padding: '8px 12px',
474
+ border: '2px solid #e1e8ed',
475
+ borderRadius: '8px',
476
+ fontSize: '14px',
477
+ background: (!currentUser || currentUser.isGuest) ? '#f8f9fa' : 'white',
478
+ cursor: (!currentUser || currentUser.isGuest) ? 'not-allowed' : 'pointer'
479
+ }}
480
+ >
481
+ <option value="general">💬 General Discussion</option>
482
+ <option value="water_test">💧 Water Quality Test</option>
483
+ <option value="biodiversity_scan">🦜 Biodiversity Discovery</option>
484
+ <option value="plant_identification">🌿 Plant Identification</option>
485
+ <option value="carbon_reduction">🌳 Carbon Reduction</option>
486
+ </select>
487
+ </div>
488
+
489
+ <form onSubmit={handlePostSubmit}>
490
+ <textarea
491
+ value={newPost}
492
+ onChange={(e) => setNewPost(e.target.value)}
493
+ placeholder={currentUser && !currentUser.isGuest
494
+ ? "Share your latest environmental discovery, test results, or eco-friendly action..."
495
+ : "Create an account to share your environmental discoveries with the community!"
496
+ }
497
+ disabled={!currentUser || currentUser.isGuest}
498
+ style={{
499
+ width: '100%',
500
+ minHeight: '100px',
501
+ padding: '15px',
502
+ border: '2px solid #e1e8ed',
503
+ borderRadius: '8px',
504
+ fontSize: '16px',
505
+ resize: 'vertical',
506
+ boxSizing: 'border-box',
507
+ fontFamily: 'inherit',
508
+ background: (!currentUser || currentUser.isGuest) ? '#f8f9fa' : 'white'
509
+ }}
510
+ />
511
+
512
+ {/* Image Preview */}
513
+ {selectedImage && (
514
+ <div style={{
515
+ marginTop: '15px',
516
+ padding: '15px',
517
+ border: '2px dashed #3498db',
518
+ borderRadius: '8px',
519
+ background: '#f8f9fa'
520
+ }}>
521
+ <div style={{ display: 'flex', alignItems: 'center', gap: '15px' }}>
522
+ <img
523
+ src={selectedImage.preview}
524
+ alt="Preview"
525
+ style={{
526
+ width: '80px',
527
+ height: '80px',
528
+ objectFit: 'cover',
529
+ borderRadius: '8px',
530
+ border: '2px solid #3498db'
531
+ }}
532
+ />
533
+ <div style={{ flex: 1 }}>
534
+ <div style={{ fontWeight: '500', color: '#2c3e50', marginBottom: '4px' }}>
535
+ {selectedImage.name}
536
+ </div>
537
+ <div style={{ fontSize: '0.85rem', color: '#7f8c8d', marginBottom: '4px' }}>
538
+ Original: {imageHandler.formatFileSize(selectedImage.file.size)}
539
+ {selectedImage.size !== selectedImage.file.size && (
540
+ <span style={{ color: '#27ae60', marginLeft: '8px' }}>
541
+ → Compressed: {imageHandler.formatFileSize(selectedImage.size)}
542
+ </span>
543
+ )}
544
+ </div>
545
+ <div style={{ fontSize: '0.8rem', color: '#3498db' }}>
546
+ ✅ Ready to upload
547
+ </div>
548
+ </div>
549
+ <button
550
+ type="button"
551
+ onClick={removeImage}
552
+ style={{
553
+ background: '#e74c3c',
554
+ color: 'white',
555
+ border: 'none',
556
+ borderRadius: '50%',
557
+ width: '30px',
558
+ height: '30px',
559
+ cursor: 'pointer',
560
+ fontSize: '16px',
561
+ display: 'flex',
562
+ alignItems: 'center',
563
+ justifyContent: 'center'
564
+ }}
565
+ title="Remove image"
566
+ >
567
+ ×
568
+ </button>
569
+ </div>
570
+ </div>
571
+ )}
572
+
573
+ {/* Location Display */}
574
+ {selectedLocation && (
575
+ <div style={{
576
+ marginTop: '10px',
577
+ padding: '10px',
578
+ background: '#e8f4fd',
579
+ borderRadius: '8px',
580
+ display: 'flex',
581
+ alignItems: 'center',
582
+ gap: '8px'
583
+ }}>
584
+ <span>📍</span>
585
+ <span style={{ color: '#2c3e50' }}>{selectedLocation}</span>
586
+ <button
587
+ type="button"
588
+ onClick={() => setSelectedLocation('')}
589
+ style={{
590
+ background: 'none',
591
+ border: 'none',
592
+ color: '#7f8c8d',
593
+ cursor: 'pointer',
594
+ marginLeft: 'auto'
595
+ }}
596
+ >
597
+ ×
598
+ </button>
599
+ </div>
600
+ )}
601
+
602
+ <div style={{
603
+ display: 'flex',
604
+ justifyContent: 'space-between',
605
+ alignItems: 'center',
606
+ marginTop: '15px'
607
+ }}>
608
+ <div style={{ display: 'flex', gap: '10px' }}>
609
+ <input
610
+ type="file"
611
+ ref={fileInputRef}
612
+ onChange={handleImageSelect}
613
+ accept="image/*"
614
+ style={{ display: 'none' }}
615
+ />
616
+ <button
617
+ type="button"
618
+ onClick={() => fileInputRef.current?.click()}
619
+ disabled={!currentUser || currentUser.isGuest}
620
+ style={{
621
+ padding: '8px 15px',
622
+ background: selectedImage ? '#27ae60' : '#ecf0f1',
623
+ color: selectedImage ? 'white' : '#2c3e50',
624
+ border: 'none',
625
+ borderRadius: '20px',
626
+ cursor: (!currentUser || currentUser.isGuest) ? 'not-allowed' : 'pointer',
627
+ fontSize: '14px',
628
+ opacity: (!currentUser || currentUser.isGuest) ? 0.5 : 1,
629
+ fontWeight: selectedImage ? '500' : 'normal'
630
+ }}
631
+ >
632
+ 📸 {selectedImage ? 'Image Added' : 'Add Photo'}
633
+ </button>
634
+ <button
635
+ type="button"
636
+ onClick={getCurrentLocation}
637
+ disabled={!currentUser || currentUser.isGuest}
638
+ style={{
639
+ padding: '8px 15px',
640
+ background: selectedLocation ? '#27ae60' : '#ecf0f1',
641
+ color: selectedLocation ? 'white' : '#2c3e50',
642
+ border: 'none',
643
+ borderRadius: '20px',
644
+ cursor: (!currentUser || currentUser.isGuest) ? 'not-allowed' : 'pointer',
645
+ fontSize: '14px',
646
+ opacity: (!currentUser || currentUser.isGuest) ? 0.5 : 1,
647
+ fontWeight: selectedLocation ? '500' : 'normal'
648
+ }}
649
+ >
650
+ 📍 {selectedLocation ? 'Location Added' : 'Add Location'}
651
+ </button>
652
+ </div>
653
+ <button
654
+ type="submit"
655
+ disabled={isLoading || !currentUser || currentUser.isGuest || !newPost.trim()}
656
+ style={{
657
+ padding: '10px 20px',
658
+ background: (isLoading || !currentUser || currentUser.isGuest || !newPost.trim()) ? '#95a5a6' : '#3498db',
659
+ color: 'white',
660
+ border: 'none',
661
+ borderRadius: '20px',
662
+ cursor: (isLoading || !currentUser || currentUser.isGuest || !newPost.trim()) ? 'not-allowed' : 'pointer',
663
+ fontSize: '16px',
664
+ fontWeight: '500'
665
+ }}
666
+ >
667
+ {isLoading ? '⏳ Posting...' : 'Share Post'}
668
+ </button>
669
+ </div>
670
+ </form>
671
+ </div>
672
+
673
+ {/* Community Posts */}
674
+ <h2 style={{ marginBottom: '20px', color: '#2c3e50' }}>📱 Recent Community Activity</h2>
675
+
676
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
677
+ {posts.map(post => (
678
+ <CommunityPost
679
+ key={post.id}
680
+ post={post}
681
+ currentUser={currentUser}
682
+ onLike={handleLike}
683
+ onComment={handleComment}
684
+ formatTimeAgo={formatTimeAgo}
685
+ getPostTypeIcon={getPostTypeIcon}
686
+ />
687
+ ))}
688
+
689
+ {posts.length === 0 && (
690
+ <div style={{
691
+ background: 'white',
692
+ borderRadius: '12px',
693
+ padding: '40px',
694
+ textAlign: 'center',
695
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
696
+ }}>
697
+ <div style={{ fontSize: '3rem', marginBottom: '15px' }}>🌱</div>
698
+ <h3 style={{ color: '#2c3e50', marginBottom: '10px' }}>No posts yet!</h3>
699
+ <p style={{ color: '#7f8c8d' }}>Be the first to share your environmental discoveries with the community.</p>
700
+ </div>
701
+ )}
702
+ </div>
703
+ </>
704
+ )}
705
+
706
+ {/* Leaderboard Tab */}
707
+ {activeTab === 'leaderboard' && (
708
+ <div style={{
709
+ background: 'white',
710
+ borderRadius: '12px',
711
+ padding: '30px',
712
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
713
+ }}>
714
+ <h2 style={{ margin: '0 0 25px 0', color: '#2c3e50', textAlign: 'center' }}>🏆 Community Leaderboard</h2>
715
+
716
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
717
+ {leaderboard.map((user, index) => (
718
+ <div key={index} style={{
719
+ display: 'flex',
720
+ alignItems: 'center',
721
+ padding: '15px',
722
+ background: user.isCurrentUser ? '#e8f4fd' : '#f8f9fa',
723
+ borderRadius: '12px',
724
+ border: user.isCurrentUser ? '2px solid #3498db' : '1px solid #e1e8ed'
725
+ }}>
726
+ <div style={{
727
+ width: '40px',
728
+ height: '40px',
729
+ borderRadius: '50%',
730
+ background: index < 3 ? '#f39c12' : '#95a5a6',
731
+ display: 'flex',
732
+ alignItems: 'center',
733
+ justifyContent: 'center',
734
+ color: 'white',
735
+ fontWeight: 'bold',
736
+ marginRight: '15px'
737
+ }}>
738
+ {index + 1}
739
+ </div>
740
+
741
+ <div style={{
742
+ width: '50px',
743
+ height: '50px',
744
+ borderRadius: '50%',
745
+ background: '#f8f9fa',
746
+ display: 'flex',
747
+ alignItems: 'center',
748
+ justifyContent: 'center',
749
+ fontSize: '1.5rem',
750
+ marginRight: '15px'
751
+ }}>
752
+ {user.avatar}
753
+ </div>
754
+
755
+ <div style={{ flex: 1 }}>
756
+ <h4 style={{ margin: '0 0 5px 0', color: '#2c3e50' }}>
757
+ {user.name} {user.isCurrentUser && '(You)'}
758
+ </h4>
759
+ <p style={{ margin: 0, color: '#7f8c8d', fontSize: '0.9rem' }}>
760
+ Level {user.level} • {user.points.toLocaleString()} points
761
+ </p>
762
+ </div>
763
+
764
+ {index < 3 && (
765
+ <div style={{ fontSize: '1.5rem' }}>
766
+ {index === 0 ? '🥇' : index === 1 ? '🥈' : '🥉'}
767
+ </div>
768
+ )}
769
+ </div>
770
+ ))}
771
+ </div>
772
+ </div>
773
+ )}
774
+
775
+ {/* Community Stats Tab */}
776
+ {activeTab === 'stats' && (
777
+ <div>
778
+ <h2 style={{ marginBottom: '25px', color: '#2c3e50', textAlign: 'center' }}>📊 Community Statistics</h2>
779
+
780
+ <div style={{
781
+ display: 'grid',
782
+ gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
783
+ gap: '20px',
784
+ marginBottom: '30px'
785
+ }}>
786
+ <div style={{
787
+ background: 'white',
788
+ padding: '25px',
789
+ borderRadius: '12px',
790
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
791
+ textAlign: 'center'
792
+ }}>
793
+ <div style={{ fontSize: '2.5rem', marginBottom: '15px' }}>🌍</div>
794
+ <h3 style={{ margin: '0 0 8px 0', color: '#27ae60', fontSize: '2rem' }}>
795
+ {communityStats.totalMembers?.toLocaleString()}
796
+ </h3>
797
+ <p style={{ margin: 0, color: '#7f8c8d', fontWeight: '600' }}>Total Members</p>
798
+ <p style={{ margin: '5px 0 0 0', color: '#27ae60', fontSize: '0.9rem' }}>
799
+ +{communityStats.activeToday} active today
800
+ </p>
801
+ </div>
802
+
803
+ <div style={{
804
+ background: 'white',
805
+ padding: '25px',
806
+ borderRadius: '12px',
807
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
808
+ textAlign: 'center'
809
+ }}>
810
+ <div style={{ fontSize: '2.5rem', marginBottom: '15px' }}>💧</div>
811
+ <h3 style={{ margin: '0 0 8px 0', color: '#3498db', fontSize: '2rem' }}>
812
+ {communityStats.waterTests?.toLocaleString()}
813
+ </h3>
814
+ <p style={{ margin: 0, color: '#7f8c8d', fontWeight: '600' }}>Water Tests Shared</p>
815
+ <p style={{ margin: '5px 0 0 0', color: '#3498db', fontSize: '0.9rem' }}>
816
+ Protecting water quality worldwide
817
+ </p>
818
+ </div>
819
+
820
+ <div style={{
821
+ background: 'white',
822
+ padding: '25px',
823
+ borderRadius: '12px',
824
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
825
+ textAlign: 'center'
826
+ }}>
827
+ <div style={{ fontSize: '2.5rem', marginBottom: '15px' }}>🦜</div>
828
+ <h3 style={{ margin: '0 0 8px 0', color: '#e67e22', fontSize: '2rem' }}>
829
+ {communityStats.speciesIdentified?.toLocaleString()}
830
+ </h3>
831
+ <p style={{ margin: 0, color: '#7f8c8d', fontWeight: '600' }}>Species Identified</p>
832
+ <p style={{ margin: '5px 0 0 0', color: '#e67e22', fontSize: '0.9rem' }}>
833
+ Biodiversity monitoring network
834
+ </p>
835
+ </div>
836
+
837
+ <div style={{
838
+ background: 'white',
839
+ padding: '25px',
840
+ borderRadius: '12px',
841
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
842
+ textAlign: 'center'
843
+ }}>
844
+ <div style={{ fontSize: '2.5rem', marginBottom: '15px' }}>🌿</div>
845
+ <h3 style={{ margin: '0 0 8px 0', color: '#27ae60', fontSize: '2rem' }}>
846
+ {communityStats.co2Saved?.toLocaleString()}
847
+ </h3>
848
+ <p style={{ margin: 0, color: '#7f8c8d', fontWeight: '600' }}>kg CO₂ Saved</p>
849
+ <p style={{ margin: '5px 0 0 0', color: '#27ae60', fontSize: '0.9rem' }}>
850
+ Collective climate action
851
+ </p>
852
+ </div>
853
+ </div>
854
+
855
+ {/* Additional Stats */}
856
+ <div style={{
857
+ display: 'grid',
858
+ gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))',
859
+ gap: '20px'
860
+ }}>
861
+ <div style={{
862
+ background: 'white',
863
+ borderRadius: '12px',
864
+ padding: '25px',
865
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
866
+ }}>
867
+ <h3 style={{ margin: '0 0 20px 0', color: '#2c3e50' }}>📈 Today's Activity</h3>
868
+ <div style={{
869
+ display: 'grid',
870
+ gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',
871
+ gap: '15px'
872
+ }}>
873
+ <div style={{ textAlign: 'center' }}>
874
+ <div style={{ fontSize: '1.6rem', color: '#3498db', fontWeight: 'bold' }}>
875
+ {communityStats.postsToday}
876
+ </div>
877
+ <div style={{ color: '#7f8c8d', fontSize: '0.9rem' }}>New Posts</div>
878
+ </div>
879
+ <div style={{ textAlign: 'center' }}>
880
+ <div style={{ fontSize: '1.6rem', color: '#27ae60', fontWeight: 'bold' }}>
881
+ {communityStats.activeToday}
882
+ </div>
883
+ <div style={{ color: '#7f8c8d', fontSize: '0.9rem' }}>Active Users</div>
884
+ </div>
885
+ <div style={{ textAlign: 'center' }}>
886
+ <div style={{ fontSize: '1.6rem', color: '#e67e22', fontWeight: 'bold' }}>
887
+ {Math.floor(communityStats.waterTests / 30)}
888
+ </div>
889
+ <div style={{ color: '#7f8c8d', fontSize: '0.9rem' }}>Tests Today</div>
890
+ </div>
891
+ </div>
892
+ </div>
893
+
894
+ <div style={{
895
+ background: 'white',
896
+ borderRadius: '12px',
897
+ padding: '25px',
898
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
899
+ }}>
900
+ <h3 style={{ margin: '0 0 20px 0', color: '#2c3e50' }}>💾 Community Storage</h3>
901
+ <div style={{
902
+ display: 'grid',
903
+ gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',
904
+ gap: '15px'
905
+ }}>
906
+ <div style={{ textAlign: 'center' }}>
907
+ <div style={{ fontSize: '1.6rem', color: '#9b59b6', fontWeight: 'bold' }}>
908
+ {imageHandler.getStorageInfo().imageCount}
909
+ </div>
910
+ <div style={{ color: '#7f8c8d', fontSize: '0.9rem' }}>Images Stored</div>
911
+ </div>
912
+ <div style={{ textAlign: 'center' }}>
913
+ <div style={{ fontSize: '1.2rem', color: '#34495e', fontWeight: 'bold' }}>
914
+ {imageHandler.getStorageInfo().formattedStorageUsed}
915
+ </div>
916
+ <div style={{ color: '#7f8c8d', fontSize: '0.9rem' }}>Storage Used</div>
917
+ </div>
918
+ <div style={{ textAlign: 'center' }}>
919
+ <button
920
+ onClick={() => {
921
+ const cleaned = imageHandler.cleanupOldImages();
922
+ alert(`Cleaned up ${cleaned} old images`);
923
+ // Refresh stats
924
+ setCommunityStats({...communityStats});
925
+ }}
926
+ style={{
927
+ background: '#95a5a6',
928
+ color: 'white',
929
+ border: 'none',
930
+ borderRadius: '6px',
931
+ padding: '8px 12px',
932
+ fontSize: '0.8rem',
933
+ cursor: 'pointer'
934
+ }}
935
+ >
936
+ 🧹 Cleanup
937
+ </button>
938
+ </div>
939
+ </div>
940
+ </div>
941
+ </div>
942
+ </div>
943
+ )}
944
+
945
+ </div>
946
+ );
947
+ };
948
+
949
+ // Community Post Component
950
+ const CommunityPost = ({ post, currentUser, onLike, onComment, formatTimeAgo, getPostTypeIcon }) => {
951
+ const [showComments, setShowComments] = useState(false);
952
+ const [newComment, setNewComment] = useState('');
953
+
954
+ const handleCommentSubmit = (e) => {
955
+ e.preventDefault();
956
+ if (newComment.trim()) {
957
+ onComment(post.id, newComment);
958
+ setNewComment('');
959
+ }
960
+ };
961
+
962
+ return (
963
+ <div style={{
964
+ background: 'white',
965
+ borderRadius: '12px',
966
+ padding: '20px',
967
+ boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
968
+ }}>
969
+ {/* Post Header */}
970
+ <div style={{
971
+ display: 'flex',
972
+ alignItems: 'center',
973
+ marginBottom: '15px'
974
+ }}>
975
+ <div style={{
976
+ width: '45px',
977
+ height: '45px',
978
+ borderRadius: '50%',
979
+ background: '#f8f9fa',
980
+ display: 'flex',
981
+ alignItems: 'center',
982
+ justifyContent: 'center',
983
+ fontSize: '1.3rem',
984
+ marginRight: '12px'
985
+ }}>
986
+ {post.avatar}
987
+ </div>
988
+ <div style={{ flex: 1 }}>
989
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
990
+ <h4 style={{ margin: '0', color: '#2c3e50' }}>{post.author}</h4>
991
+ <span style={{ fontSize: '1rem' }}>{getPostTypeIcon(post.type)}</span>
992
+ </div>
993
+ <p style={{ margin: '2px 0 0 0', fontSize: '0.9rem', color: '#7f8c8d' }}>
994
+ {formatTimeAgo(post.timestamp)}
995
+ {post.location && <span> • 📍 {post.location}</span>}
996
+ </p>
997
+ </div>
998
+ </div>
999
+
1000
+ {/* Post Content */}
1001
+ <p style={{
1002
+ margin: '0 0 15px 0',
1003
+ lineHeight: '1.6',
1004
+ color: '#2c3e50',
1005
+ fontSize: '1rem'
1006
+ }}>
1007
+ {post.content}
1008
+ </p>
1009
+
1010
+ {/* Post Image */}
1011
+ {post.image && (
1012
+ <div style={{
1013
+ marginBottom: '15px',
1014
+ borderRadius: '12px',
1015
+ overflow: 'hidden',
1016
+ border: '1px solid #e1e8ed'
1017
+ }}>
1018
+ <img
1019
+ src={post.image.url}
1020
+ alt="Post content"
1021
+ style={{
1022
+ width: '100%',
1023
+ maxHeight: '400px',
1024
+ objectFit: 'cover',
1025
+ display: 'block'
1026
+ }}
1027
+ />
1028
+ </div>
1029
+ )}
1030
+
1031
+ {/* Post Data (if available) */}
1032
+ {post.data && Object.keys(post.data).length > 0 && (
1033
+ <div style={{
1034
+ background: '#f8f9fa',
1035
+ padding: '15px',
1036
+ borderRadius: '8px',
1037
+ marginBottom: '15px',
1038
+ fontSize: '0.9rem',
1039
+ border: '1px solid #e1e8ed'
1040
+ }}>
1041
+ {post.type === 'water_test' && post.data.ph && (
1042
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
1043
+ <div style={{ fontWeight: 'bold', color: '#3498db', marginBottom: '5px' }}>
1044
+ 💧 Water Test Results
1045
+ </div>
1046
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: '10px' }}>
1047
+ <div style={{ background: 'white', padding: '8px', borderRadius: '6px', textAlign: 'center' }}>
1048
+ <div style={{ fontWeight: 'bold', color: '#2c3e50' }}>pH Level</div>
1049
+ <div style={{ color: '#3498db', fontSize: '1.1rem' }}>{post.data.ph}</div>
1050
+ </div>
1051
+ <div style={{ background: 'white', padding: '8px', borderRadius: '6px', textAlign: 'center' }}>
1052
+ <div style={{ fontWeight: 'bold', color: '#2c3e50' }}>Nitrates</div>
1053
+ <div style={{ color: '#e67e22', fontSize: '1.1rem' }}>{post.data.nitrates}ppm</div>
1054
+ </div>
1055
+ {post.data.chlorine && (
1056
+ <div style={{ background: 'white', padding: '8px', borderRadius: '6px', textAlign: 'center' }}>
1057
+ <div style={{ fontWeight: 'bold', color: '#2c3e50' }}>Chlorine</div>
1058
+ <div style={{ color: '#27ae60', fontSize: '1.1rem' }}>{post.data.chlorine}ppm</div>
1059
+ </div>
1060
+ )}
1061
+ </div>
1062
+ </div>
1063
+ )}
1064
+ {post.type === 'biodiversity_scan' && post.data.speciesCount && (
1065
+ <div>
1066
+ <div style={{ fontWeight: 'bold', color: '#e67e22', marginBottom: '8px' }}>
1067
+ 🦜 Biodiversity Scan Results
1068
+ </div>
1069
+ <div style={{ display: 'flex', gap: '15px', alignItems: 'center' }}>
1070
+ <div style={{ background: 'white', padding: '8px 12px', borderRadius: '6px' }}>
1071
+ <strong>{post.data.speciesCount}</strong> species identified
1072
+ </div>
1073
+ {post.data.rareSpecies && (
1074
+ <div style={{ background: '#fff3cd', padding: '8px 12px', borderRadius: '6px', color: '#856404' }}>
1075
+ ⭐ Rare: {post.data.rareSpecies}
1076
+ </div>
1077
+ )}
1078
+ </div>
1079
+ </div>
1080
+ )}
1081
+ {post.type === 'carbon_reduction' && post.data.co2Saved && (
1082
+ <div>
1083
+ <div style={{ fontWeight: 'bold', color: '#27ae60', marginBottom: '8px' }}>
1084
+ 🌳 Carbon Impact Results
1085
+ </div>
1086
+ <div style={{ display: 'flex', gap: '15px', alignItems: 'center' }}>
1087
+ <div style={{ background: 'white', padding: '8px 12px', borderRadius: '6px' }}>
1088
+ <strong>{post.data.co2Saved}kg</strong> CO₂ saved
1089
+ </div>
1090
+ <div style={{ background: 'white', padding: '8px 12px', borderRadius: '6px' }}>
1091
+ <strong>{post.data.reduction}%</strong> reduction
1092
+ </div>
1093
+ </div>
1094
+ </div>
1095
+ )}
1096
+ {post.type === 'plant_identification' && post.data.species && (
1097
+ <div>
1098
+ <div style={{ fontWeight: 'bold', color: '#27ae60', marginBottom: '8px' }}>
1099
+ 🌿 Plant Identification
1100
+ </div>
1101
+ <div style={{ display: 'flex', gap: '15px', alignItems: 'center' }}>
1102
+ <div style={{ background: 'white', padding: '8px 12px', borderRadius: '6px' }}>
1103
+ Species: <strong>{post.data.species}</strong>
1104
+ </div>
1105
+ {post.data.confidence && (
1106
+ <div style={{ background: 'white', padding: '8px 12px', borderRadius: '6px' }}>
1107
+ Confidence: <strong>{post.data.confidence}%</strong>
1108
+ </div>
1109
+ )}
1110
+ </div>
1111
+ </div>
1112
+ )}
1113
+ </div>
1114
+ )}
1115
+
1116
+ {/* Post Actions */}
1117
+ <div style={{
1118
+ display: 'flex',
1119
+ alignItems: 'center',
1120
+ gap: '20px',
1121
+ paddingTop: '15px',
1122
+ borderTop: '1px solid #ecf0f1'
1123
+ }}>
1124
+ <button
1125
+ onClick={() => onLike(post.id)}
1126
+ disabled={!currentUser || currentUser.isGuest}
1127
+ style={{
1128
+ background: 'none',
1129
+ border: 'none',
1130
+ cursor: (!currentUser || currentUser.isGuest) ? 'not-allowed' : 'pointer',
1131
+ display: 'flex',
1132
+ alignItems: 'center',
1133
+ gap: '5px',
1134
+ color: '#7f8c8d',
1135
+ fontSize: '14px',
1136
+ opacity: (!currentUser || currentUser.isGuest) ? 0.5 : 1
1137
+ }}
1138
+ >
1139
+ ❤️ {post.likes} Likes
1140
+ </button>
1141
+ <button
1142
+ onClick={() => setShowComments(!showComments)}
1143
+ style={{
1144
+ background: 'none',
1145
+ border: 'none',
1146
+ cursor: 'pointer',
1147
+ display: 'flex',
1148
+ alignItems: 'center',
1149
+ gap: '5px',
1150
+ color: '#7f8c8d',
1151
+ fontSize: '14px'
1152
+ }}
1153
+ >
1154
+ 💬 {post.comments.length} Comments
1155
+ </button>
1156
+ <button style={{
1157
+ background: 'none',
1158
+ border: 'none',
1159
+ cursor: 'pointer',
1160
+ display: 'flex',
1161
+ alignItems: 'center',
1162
+ gap: '5px',
1163
+ color: '#7f8c8d',
1164
+ fontSize: '14px'
1165
+ }}>
1166
+ 🔄 Share
1167
+ </button>
1168
+ </div>
1169
+
1170
+ {/* Comments Section */}
1171
+ {showComments && (
1172
+ <div style={{
1173
+ marginTop: '15px',
1174
+ paddingTop: '15px',
1175
+ borderTop: '1px solid #ecf0f1'
1176
+ }}>
1177
+ {/* Existing Comments */}
1178
+ {post.comments.map((comment, index) => (
1179
+ <div key={index} style={{
1180
+ display: 'flex',
1181
+ gap: '10px',
1182
+ marginBottom: '12px',
1183
+ padding: '10px',
1184
+ background: '#f8f9fa',
1185
+ borderRadius: '8px'
1186
+ }}>
1187
+ <div style={{
1188
+ width: '30px',
1189
+ height: '30px',
1190
+ borderRadius: '50%',
1191
+ background: '#e9ecef',
1192
+ display: 'flex',
1193
+ alignItems: 'center',
1194
+ justifyContent: 'center',
1195
+ fontSize: '0.8rem'
1196
+ }}>
1197
+ 👤
1198
+ </div>
1199
+ <div style={{ flex: 1 }}>
1200
+ <div style={{ fontWeight: 'bold', fontSize: '0.9rem', marginBottom: '2px' }}>
1201
+ {comment.author}
1202
+ </div>
1203
+ <div style={{ fontSize: '0.9rem', color: '#2c3e50' }}>
1204
+ {comment.content}
1205
+ </div>
1206
+ <div style={{ fontSize: '0.8rem', color: '#7f8c8d', marginTop: '2px' }}>
1207
+ {formatTimeAgo(comment.timestamp)}
1208
+ </div>
1209
+ </div>
1210
+ </div>
1211
+ ))}
1212
+
1213
+ {/* Add Comment Form */}
1214
+ {currentUser && !currentUser.isGuest ? (
1215
+ <form onSubmit={handleCommentSubmit} style={{ marginTop: '10px' }}>
1216
+ <div style={{ display: 'flex', gap: '10px' }}>
1217
+ <input
1218
+ type="text"
1219
+ value={newComment}
1220
+ onChange={(e) => setNewComment(e.target.value)}
1221
+ placeholder="Write a comment..."
1222
+ style={{
1223
+ flex: 1,
1224
+ padding: '8px 12px',
1225
+ border: '1px solid #e1e8ed',
1226
+ borderRadius: '20px',
1227
+ fontSize: '14px'
1228
+ }}
1229
+ />
1230
+ <button
1231
+ type="submit"
1232
+ disabled={!newComment.trim()}
1233
+ style={{
1234
+ padding: '8px 16px',
1235
+ background: newComment.trim() ? '#3498db' : '#95a5a6',
1236
+ color: 'white',
1237
+ border: 'none',
1238
+ borderRadius: '20px',
1239
+ cursor: newComment.trim() ? 'pointer' : 'not-allowed',
1240
+ fontSize: '14px'
1241
+ }}
1242
+ >
1243
+ Post
1244
+ </button>
1245
+ </div>
1246
+ </form>
1247
+ ) : (
1248
+ <div style={{
1249
+ textAlign: 'center',
1250
+ padding: '10px',
1251
+ color: '#7f8c8d',
1252
+ fontSize: '0.9rem'
1253
+ }}>
1254
+ <a href="#" onClick={(e) => { e.preventDefault(); /* Navigate to login */ }} style={{ color: '#3498db' }}>
1255
+ Create an account
1256
+ </a> to join the conversation
1257
+ </div>
1258
+ )}
1259
+ </div>
1260
+ )}
1261
+ </div>
1262
+ );
1263
+ };
1264
+
1265
+ export default Community;