feat: add country and city fields to user profile
- Add country and city fields to User model - Create database migration for location fields - Add validation for country and city (max 100 characters) - Create countries.js with complete list of 195 countries - Add country dropdown select and city text input to profile page - Include country and city in GET /api/users/me response - Update profile form to support location data Users can now select their country from a dropdown list of all countries and enter their city name.
This commit is contained in:
@@ -2,7 +2,8 @@ import { useState, useEffect } from 'react';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
import { authAPI } from '../services/api';
|
||||
import Layout from '../components/layout/Layout';
|
||||
import { User, Mail, Lock, Save, AlertCircle, CheckCircle, Loader2, Hash, Youtube, Instagram, Facebook } from 'lucide-react';
|
||||
import { User, Mail, Lock, Save, AlertCircle, CheckCircle, Loader2, Hash, Youtube, Instagram, Facebook, MapPin, Globe } from 'lucide-react';
|
||||
import { COUNTRIES } from '../data/countries';
|
||||
|
||||
const ProfilePage = () => {
|
||||
const { user, updateUser } = useAuth();
|
||||
@@ -18,6 +19,8 @@ const ProfilePage = () => {
|
||||
instagramUrl: '',
|
||||
facebookUrl: '',
|
||||
tiktokUrl: '',
|
||||
country: '',
|
||||
city: '',
|
||||
});
|
||||
|
||||
// Load user data when component mounts or user changes
|
||||
@@ -32,6 +35,8 @@ const ProfilePage = () => {
|
||||
instagramUrl: user.instagramUrl || '',
|
||||
facebookUrl: user.facebookUrl || '',
|
||||
tiktokUrl: user.tiktokUrl || '',
|
||||
country: user.country || '',
|
||||
city: user.city || '',
|
||||
});
|
||||
}
|
||||
}, [user]);
|
||||
@@ -231,6 +236,54 @@ const ProfilePage = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Location Section */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* Country */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Country
|
||||
</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<Globe className="h-5 w-5 text-gray-400" />
|
||||
</div>
|
||||
<select
|
||||
name="country"
|
||||
value={profileData.country}
|
||||
onChange={handleProfileChange}
|
||||
className="pl-10 w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-primary-500 focus:border-primary-500"
|
||||
>
|
||||
<option value="">Select a country</option>
|
||||
{COUNTRIES.map((country) => (
|
||||
<option key={country} value={country}>
|
||||
{country}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* City */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
City
|
||||
</label>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<MapPin className="h-5 w-5 text-gray-400" />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="city"
|
||||
value={profileData.city}
|
||||
onChange={handleProfileChange}
|
||||
className="pl-10 w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-primary-500 focus:border-primary-500"
|
||||
placeholder="Somewhere"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* WSDC ID */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
|
||||
Reference in New Issue
Block a user