Skip to content

Commit 54ba776

Browse files
Refactor location data input
Replaced GeoPoint with country/state dropdowns for location input.
1 parent ea9c304 commit 54ba776

File tree

4 files changed

+258
-82
lines changed

4 files changed

+258
-82
lines changed

src/components/CommunityMap.tsx

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
21
import React, { useEffect, useState } from 'react';
32
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
43
import 'leaflet/dist/leaflet.css';
54
import L from 'leaflet';
65
import { getCommunityLocations } from '../utils/firebase';
76
import { cn } from '@/lib/utils';
7+
import { countries, usStates } from '@/utils/locationData';
88

99
// Fix Leaflet marker icon issue
1010
delete (L.Icon.Default.prototype as any)._getIconUrl;
@@ -29,23 +29,81 @@ interface CommunityMapProps {
2929
className?: string;
3030
}
3131

32+
// Approximate country center coordinates
33+
const countryCoordinates: Record<string, [number, number]> = {
34+
'us': [37.0902, -95.7129], // USA
35+
'ca': [56.1304, -106.3468], // Canada
36+
'gb': [55.3781, -3.4360], // UK
37+
'au': [-25.2744, 133.7751], // Australia
38+
'de': [51.1657, 10.4515], // Germany
39+
'fr': [46.2276, 2.2137], // France
40+
'jp': [36.2048, 138.2529], // Japan
41+
'cn': [35.8617, 104.1954], // China
42+
'in': [20.5937, 78.9629], // India
43+
'br': [-14.2350, -51.9253], // Brazil
44+
'mx': [23.6345, -102.5528], // Mexico
45+
// Default for other countries
46+
'default': [0, 0]
47+
};
48+
49+
// US states approximate coordinates
50+
const stateCoordinates: Record<string, [number, number]> = {
51+
'AL': [32.7794, -86.8287],
52+
'AK': [64.0685, -152.2782],
53+
'AZ': [34.2744, -111.6602],
54+
'AR': [34.8938, -92.4426],
55+
'CA': [36.7783, -119.4179],
56+
'CO': [39.5501, -105.7821],
57+
'CT': [41.6032, -73.0877],
58+
'DE': [38.9896, -75.5050],
59+
'FL': [27.9944, -81.7603],
60+
'GA': [32.6415, -83.4426],
61+
// ... other states can be added similarly
62+
'default': [39.8333, -98.5833] // Center of US roughly
63+
};
64+
3265
const CommunityMap: React.FC<CommunityMapProps> = ({ className }) => {
33-
const [locations, setLocations] = useState<Array<{ id: string; location: { latitude: number; longitude: number } }>>([]);
66+
const [locations, setLocations] = useState<Array<{ id: string; coordinates: [number, number]; displayName: string }>>([]);
3467
const [isLoading, setIsLoading] = useState(true);
3568

3669
useEffect(() => {
3770
const fetchLocations = async () => {
3871
try {
3972
const communityLocations = await getCommunityLocations();
4073

41-
// Transform GeoPoint to latitude/longitude objects
42-
const formattedLocations = communityLocations.map(item => ({
43-
id: item.id,
44-
location: {
45-
latitude: item.location.latitude,
46-
longitude: item.location.longitude
74+
// Transform country/state data to map coordinates
75+
const formattedLocations = communityLocations.map(item => {
76+
const countryCode = item.location.country;
77+
const stateCode = item.location.state;
78+
79+
// Get the country name for display
80+
const countryObj = countries.find(c => c.value === countryCode);
81+
let displayName = countryObj?.label || 'Unknown Country';
82+
83+
// If it's US and has a state, use state coordinates and add state to display name
84+
let coordinates: [number, number] = countryCoordinates[countryCode] || countryCoordinates.default;
85+
86+
if (countryCode === 'us' && stateCode) {
87+
coordinates = stateCoordinates[stateCode] || stateCoordinates.default;
88+
const stateObj = usStates.find(s => s.value === stateCode);
89+
if (stateObj) {
90+
displayName = `${displayName}, ${stateObj.label}`;
91+
}
4792
}
48-
}));
93+
94+
// Add a small random offset for privacy and to prevent markers from overlapping
95+
const randomOffset = () => (Math.random() - 0.5) * 2;
96+
coordinates = [
97+
coordinates[0] + randomOffset(),
98+
coordinates[1] + randomOffset()
99+
];
100+
101+
return {
102+
id: item.id,
103+
coordinates,
104+
displayName
105+
};
106+
});
49107

50108
setLocations(formattedLocations);
51109
} catch (error) {
@@ -87,11 +145,11 @@ const CommunityMap: React.FC<CommunityMapProps> = ({ className }) => {
87145
{locations.map((item) => (
88146
<Marker
89147
key={item.id}
90-
position={[item.location.latitude, item.location.longitude]}
148+
position={item.coordinates}
91149
icon={customIcon}
92150
>
93151
<Popup>
94-
A community member is here
152+
A community member from {item.displayName}
95153
</Popup>
96154
</Marker>
97155
))}

src/pages/Register.tsx

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
SelectTrigger,
1717
SelectValue,
1818
} from "@/components/ui/select";
19+
import { countries, usStates } from '@/utils/locationData';
1920

2021
const Register: React.FC = () => {
2122
const [email, setEmail] = useState('');
@@ -25,6 +26,8 @@ const Register: React.FC = () => {
2526
const [firstName, setFirstName] = useState('');
2627
const [lastName, setLastName] = useState('');
2728
const [gender, setGender] = useState('prefer-not-to-say');
29+
const [country, setCountry] = useState('');
30+
const [state, setState] = useState('');
2831
const [isLoading, setIsLoading] = useState(false);
2932
const [error, setError] = useState<string | null>(null);
3033
const [termsAccepted, setTermsAccepted] = useState(false);
@@ -65,31 +68,27 @@ const Register: React.FC = () => {
6568
setError('You must accept the Terms of Service and Privacy Policy');
6669
return;
6770
}
71+
72+
if (!country) {
73+
setError('Please select your country');
74+
return;
75+
}
76+
77+
// If the country is US, state is required
78+
if (country === 'us' && !state) {
79+
setError('Please select your state');
80+
return;
81+
}
6882

6983
setIsLoading(true);
7084
setError(null);
7185

7286
try {
73-
// Get approximate location (using browser geolocation)
74-
let location;
75-
76-
try {
77-
const position = await new Promise<GeolocationPosition>((resolve, reject) => {
78-
navigator.geolocation.getCurrentPosition(resolve, reject, {
79-
enableHighAccuracy: false,
80-
timeout: 5000,
81-
maximumAge: 0
82-
});
83-
});
84-
85-
location = {
86-
lat: position.coords.latitude,
87-
lng: position.coords.longitude
88-
};
89-
} catch (err) {
90-
console.log('Geolocation not available or denied', err);
91-
// Continue without location
92-
}
87+
// Create location object with country and state (if applicable)
88+
const location = {
89+
country,
90+
state: country === 'us' ? state : null
91+
};
9392

9493
const success = await register(email, password, username, firstName, lastName, gender, location);
9594
if (success) {
@@ -186,10 +185,57 @@ const Register: React.FC = () => {
186185
<SelectContent>
187186
<SelectItem value="male">Male</SelectItem>
188187
<SelectItem value="female">Female</SelectItem>
188+
<SelectItem value="other">Other</SelectItem>
189+
<SelectItem value="prefer-not-to-say">Prefer not to say</SelectItem>
189190
</SelectContent>
190191
</Select>
191192
</div>
192193

194+
<div className="space-y-2">
195+
<Label htmlFor="country">Country</Label>
196+
<Select
197+
value={country}
198+
onValueChange={(value) => {
199+
setCountry(value);
200+
if (value !== 'us') {
201+
setState('');
202+
}
203+
}}
204+
>
205+
<SelectTrigger className="w-full">
206+
<SelectValue placeholder="Select your country" />
207+
</SelectTrigger>
208+
<SelectContent className="max-h-[200px]">
209+
{countries.map((country) => (
210+
<SelectItem key={country.value} value={country.value}>
211+
{country.label}
212+
</SelectItem>
213+
))}
214+
</SelectContent>
215+
</Select>
216+
</div>
217+
218+
{country === 'us' && (
219+
<div className="space-y-2">
220+
<Label htmlFor="state">State</Label>
221+
<Select
222+
value={state}
223+
onValueChange={setState}
224+
>
225+
<SelectTrigger className="w-full">
226+
<SelectValue placeholder="Select your state" />
227+
</SelectTrigger>
228+
<SelectContent className="max-h-[200px]">
229+
{usStates.map((state) => (
230+
<SelectItem key={state.value} value={state.value}>
231+
{state.label}
232+
</SelectItem>
233+
))}
234+
</SelectContent>
235+
</Select>
236+
</div>
237+
)}
238+
193239
<div className="space-y-2">
194240
<Label htmlFor="password">Password</Label>
195241
<Input

src/utils/firebase.ts

Lines changed: 16 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import { initializeApp } from 'firebase/app';
32
import { getAuth, onAuthStateChanged, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, User, updatePassword, EmailAuthProvider, reauthenticateWithCredential } from 'firebase/auth';
43
import { getFirestore, collection, doc, setDoc, getDoc, getDocs, updateDoc, query, where, GeoPoint, Timestamp, addDoc, orderBy, arrayUnion } from 'firebase/firestore';
@@ -12,7 +11,10 @@ export interface UserProfile {
1211
username?: string;
1312
email?: string;
1413
gender?: 'male' | 'female' | 'other' | 'prefer-not-to-say';
15-
location?: GeoPoint;
14+
location?: {
15+
country: string;
16+
state?: string | null;
17+
};
1618
role?: 'admin' | 'member';
1719
joinedAt?: Timestamp;
1820
streakDays?: number;
@@ -98,7 +100,15 @@ export const login = async (email: string, password: string) => {
98100
}
99101
};
100102

101-
export const register = async (email: string, password: string, username: string, firstName: string, lastName: string, gender: string, location?: { lat: number, lng: number }) => {
103+
export const register = async (
104+
email: string,
105+
password: string,
106+
username: string,
107+
firstName: string,
108+
lastName: string,
109+
gender: string,
110+
location?: { country: string; state?: string | null }
111+
) => {
102112
try {
103113
console.log('Registering user with gender:', gender);
104114
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
@@ -112,7 +122,7 @@ export const register = async (email: string, password: string, username: string
112122
meditations: [],
113123
relapses: [],
114124
gender,
115-
location: location ? new GeoPoint(location.lat, location.lng) : null,
125+
location: location || null,
116126
role: 'member', // Default role
117127
joinedAt: Timestamp.now(),
118128
streakDays: 0,
@@ -276,7 +286,6 @@ interface LogRelapseResult {
276286
message?: string;
277287
}
278288

279-
280289
export const logRelapse = async (userId: string, triggers: string, notes?: string): Promise<LogRelapseResult> => {
281290
try {
282291
const userDocRef = doc(db, 'users', userId); // Reference to the user's document
@@ -297,61 +306,17 @@ export const logRelapse = async (userId: string, triggers: string, notes?: strin
297306
}
298307
};
299308

300-
// Get user triggers from the last 7 days
301-
// export const getUserTriggers = async (userId: string): Promise<{ name: string; count: number; }[]> => {
302-
// try {
303-
// const sevenDaysAgo = new Date();
304-
// sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
305-
306-
// const relapsesRef = collection(db, 'relapses');
307-
// const q = query(
308-
// relapsesRef,
309-
// where('userId', '==', userId),
310-
// where('timestamp', '>=', Timestamp.fromDate(sevenDaysAgo)),
311-
// orderBy('timestamp', 'desc')
312-
// );
313-
314-
// const querySnapshot = await getDocs(q);
315-
316-
// // Count the triggers
317-
// const triggerCounts: Record<string, number> = {};
318-
319-
// querySnapshot.forEach((doc) => {
320-
// const data = doc.data();
321-
// if (data.triggers && Array.isArray(data.triggers)) {
322-
// data.triggers.forEach(trigger => {
323-
// triggerCounts[trigger] = (triggerCounts[trigger] || 0) + 1;
324-
// });
325-
// }
326-
// });
327-
328-
// // Convert to array format for chart
329-
// const triggers = Object.entries(triggerCounts).map(([name, count]) => ({
330-
// name,
331-
// count
332-
// }));
333-
334-
// // Sort by count (descending)
335-
// triggers.sort((a, b) => b.count - a.count);
336-
337-
// return triggers;
338-
// } catch (error) {
339-
// console.error('Error fetching user triggers:', error);
340-
// return [];
341-
// }
342-
// };
343-
344309
// Community map data (anonymized)
345310
export const getCommunityLocations = async () => {
346311
try {
347312
const usersRef = collection(db, 'users');
348313
const querySnapshot = await getDocs(usersRef);
349314

350-
const locations: { id: string; location: GeoPoint }[] = [];
315+
const locations: { id: string; location: { country: string; state?: string | null; } }[] = [];
351316

352317
querySnapshot.forEach((doc) => {
353318
const data = doc.data();
354-
if (data.location) {
319+
if (data.location && data.location.country) {
355320
// Only include location data, not user identifiable information
356321
locations.push({
357322
id: doc.id,

0 commit comments

Comments
 (0)