feat: add social media links to user profile

- Add YouTube, Instagram, Facebook, and TikTok URL fields to User model
- Create database migration for social media link columns
- Add custom validators to ensure URLs contain correct domains
- Update profile page with social media input fields
- Include social media URLs in GET /api/users/me response
- Add icons for each social platform in the UI

Users can now add links to their social media profiles. Each field
validates that the URL contains the appropriate domain (e.g.,
instagram.com for Instagram, youtube.com/youtu.be for YouTube).
This commit is contained in:
Radosław Gierwiało
2025-11-13 20:47:57 +01:00
parent ebf4b84ed2
commit 48f9dfe1b4
6 changed files with 150 additions and 2 deletions

View File

@@ -2,7 +2,7 @@ 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 } from 'lucide-react';
import { User, Mail, Lock, Save, AlertCircle, CheckCircle, Loader2, Hash, Youtube, Instagram, Facebook } from 'lucide-react';
const ProfilePage = () => {
const { user, updateUser } = useAuth();
@@ -14,6 +14,10 @@ const ProfilePage = () => {
lastName: '',
email: '',
wsdcId: '',
youtubeUrl: '',
instagramUrl: '',
facebookUrl: '',
tiktokUrl: '',
});
// Load user data when component mounts or user changes
@@ -24,6 +28,10 @@ const ProfilePage = () => {
lastName: user.lastName || '',
email: user.email || '',
wsdcId: user.wsdcId || '',
youtubeUrl: user.youtubeUrl || '',
instagramUrl: user.instagramUrl || '',
facebookUrl: user.facebookUrl || '',
tiktokUrl: user.tiktokUrl || '',
});
}
}, [user]);
@@ -272,6 +280,95 @@ const ProfilePage = () => {
</p>
</div>
{/* Social Media Links Section */}
<div className="pt-4 border-t border-gray-200">
<h3 className="text-lg font-medium text-gray-900 mb-4">Social Media Links</h3>
<div className="space-y-4">
{/* YouTube */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
YouTube
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Youtube className="h-5 w-5 text-gray-400" />
</div>
<input
type="url"
name="youtubeUrl"
value={profileData.youtubeUrl}
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="https://youtube.com/@yourhandle"
/>
</div>
</div>
{/* Instagram */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Instagram
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Instagram className="h-5 w-5 text-gray-400" />
</div>
<input
type="url"
name="instagramUrl"
value={profileData.instagramUrl}
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="https://instagram.com/yourhandle"
/>
</div>
</div>
{/* Facebook */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Facebook
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Facebook className="h-5 w-5 text-gray-400" />
</div>
<input
type="url"
name="facebookUrl"
value={profileData.facebookUrl}
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="https://facebook.com/yourhandle"
/>
</div>
</div>
{/* TikTok */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
TikTok
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg className="h-5 w-5 text-gray-400" viewBox="0 0 24 24" fill="currentColor">
<path d="M19.59 6.69a4.83 4.83 0 0 1-3.77-4.25V2h-3.45v13.67a2.89 2.89 0 0 1-5.2 1.74 2.89 2.89 0 0 1 2.31-4.64 2.93 2.93 0 0 1 .88.13V9.4a6.84 6.84 0 0 0-1-.05A6.33 6.33 0 0 0 5 20.1a6.34 6.34 0 0 0 10.86-4.43v-7a8.16 8.16 0 0 0 4.77 1.52v-3.4a4.85 4.85 0 0 1-1-.1z"/>
</svg>
</div>
<input
type="url"
name="tiktokUrl"
value={profileData.tiktokUrl}
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="https://tiktok.com/@yourhandle"
/>
</div>
</div>
</div>
</div>
{/* Submit Button */}
<button
type="submit"