Spaces:
Configuration error
Configuration error
| import React, { useState, ChangeEvent, useContext } from 'react'; | |
| import { Camera, Edit3, Save, X, Calendar, Globe } from 'lucide-react'; | |
| import { UserProfile } from '../types/user'; | |
| import { ThemeContext } from '../contexts/ThemeContext'; | |
| interface ProfileHeaderProps { | |
| user: UserProfile; | |
| isEditing: boolean; | |
| editForm: any; | |
| setEditForm: (form: any) => void; | |
| onEdit: () => void; | |
| onSave: () => void; | |
| onCancel: () => void; | |
| onAvatarChange: (file: File) => void; | |
| } | |
| const ProfileHeader: React.FC<ProfileHeaderProps> = ({ | |
| user, | |
| isEditing, | |
| editForm, | |
| setEditForm, | |
| onEdit, | |
| onSave, | |
| onCancel, | |
| onAvatarChange, | |
| }) => { | |
| const { theme } = useContext(ThemeContext); // ✅ ThemeContext | |
| const [avatarPreview, setAvatarPreview] = useState(user.avatar); | |
| const handleAvatarUpload = (e: ChangeEvent<HTMLInputElement>) => { | |
| if (e.target.files?.[0]) { | |
| const file = e.target.files[0]; | |
| setAvatarPreview(URL.createObjectURL(file)); | |
| onAvatarChange(file); | |
| } | |
| }; | |
| // Inputs still adapt to theme | |
| const inputBg = theme === 'dark' | |
| ? 'bg-gray-800 text-white placeholder-gray-400' | |
| : 'bg-gray-100 text-gray-900 placeholder-gray-500'; | |
| return ( | |
| <div className="relative rounded-2xl overflow-hidden shadow-sm"> | |
| {/* Gradient Background */} | |
| <div | |
| className="absolute inset-0 z-0" | |
| style={{ background: 'linear-gradient(to right, #1e3a8a, #0f172a)' }} | |
| /> | |
| <div className="relative px-6 pb-6 pt-6 sm:pt-12 flex flex-col sm:flex-row items-start sm:items-end gap-6 z-10"> | |
| {/* Avatar */} | |
| <div className="relative"> | |
| <img | |
| src={avatarPreview || 'https://via.placeholder.com/150'} | |
| alt={`${user.name || 'User'} Profile Picture`} | |
| title={`${user.name || 'User'}'s profile avatar - Click camera icon to change`} | |
| className="w-40 h-40 rounded-2xl object-cover border-0 shadow-lg" | |
| /> | |
| <label className="absolute -bottom-2 -right-2 bg-blue-600 text-white p-2 rounded-xl hover:bg-blue-700 cursor-pointer transition shadow-lg"> | |
| <Camera className="w-4 h-4" /> | |
| <input type="file" className="hidden" onChange={handleAvatarUpload} /> | |
| </label> | |
| </div> | |
| {/* Name, Email, Username, Bio */} | |
| <div className="flex-1 pt-16 sm:pt-4 text-left"> | |
| {isEditing ? ( | |
| <div className="space-y-4"> | |
| <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> | |
| <input | |
| value={editForm.name} | |
| onChange={(e) => setEditForm({ ...editForm, name: e.target.value })} | |
| className={`px-4 py-3 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${inputBg}`} | |
| placeholder="Full Name" | |
| /> | |
| <input | |
| value={editForm.nickname} | |
| onChange={(e) => setEditForm({ ...editForm, nickname: e.target.value })} | |
| className={`px-4 py-3 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${inputBg}`} | |
| placeholder="Nickname" | |
| /> | |
| </div> | |
| <textarea | |
| value={editForm.bio} | |
| onChange={(e) => setEditForm({ ...editForm, bio: e.target.value })} | |
| rows={3} | |
| className={`w-full px-4 py-3 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent resize-none ${inputBg}`} | |
| placeholder="Tell us about yourself..." | |
| /> | |
| </div> | |
| ) : ( | |
| <div className="text-white"> | |
| <h1 className="text-3xl font-bold mb-1">{user.name}</h1> | |
| <p className="text-sm mb-1">{user.email}</p> | |
| <p className="text-lg mb-2">@{user.username}</p> | |
| <p className="mb-4 max-w-2xl">{user.bio}</p> | |
| <div className="flex flex-wrap items-center gap-4 text-sm"> | |
| <div className="flex items-center gap-1"> | |
| <Calendar className="w-4 h-4 text-white" /> | |
| <span>Joined {user.joinDate}</span> | |
| </div> | |
| <div className="flex items-center gap-1"> | |
| <Globe className="w-4 h-4 text-white" /> | |
| <span>Last active: {user.lastActive}</span> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| {/* Action Buttons */} | |
| <div className="flex gap-3 pt-4 sm:pt-0 flex-col sm:flex-row"> | |
| {isEditing ? ( | |
| <> | |
| <button | |
| onClick={onSave} | |
| className="flex items-center gap-2 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition font-medium" | |
| > | |
| <Save className="w-4 h-4" /> Save Changes | |
| </button> | |
| <button | |
| onClick={onCancel} | |
| className="flex items-center gap-2 px-6 py-2 rounded-lg hover:bg-gray-200 transition font-medium" | |
| > | |
| <X className="w-4 h-4" /> Cancel | |
| </button> | |
| </> | |
| ) : ( | |
| <button | |
| onClick={onEdit} | |
| className="flex items-center gap-2 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition font-medium" | |
| > | |
| <Edit3 className="w-4 h-4" /> Edit Profile | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default ProfileHeader; | |