← back to Dear Bubbe Nextjs
components/ProfileSettings.tsx
514 lines
'use client'
import { useState, useEffect } from 'react'
import { useSession } from 'next-auth/react'
interface ProfileSettingsProps {
isOpen: boolean
onClose: () => void
userProfile: any
onProfileUpdate: (profile: any) => void
}
export default function ProfileSettings({ isOpen, onClose, userProfile, onProfileUpdate }: ProfileSettingsProps) {
const { data: session } = useSession()
const [formData, setFormData] = useState({
preferredName: '',
gender: '',
relationshipStatus: '',
birthYear: '',
religiousLevel: '',
hasKids: '',
numberOfKids: 0,
incomeLevel: '',
education: '',
school: '',
degree: '',
jobTitle: '',
company: '',
industry: '',
country: '',
state: '',
city: ''
})
const [isSaving, setIsSaving] = useState(false)
const [saveMessage, setSaveMessage] = useState('')
useEffect(() => {
console.log('[ProfileSettings] Received userProfile:', userProfile)
if (userProfile) {
const loadedData = {
preferredName: userProfile.preferredName || '',
gender: userProfile.gender || '',
relationshipStatus: userProfile.relationshipStatus || '',
birthYear: userProfile.birthYear || '',
religiousLevel: userProfile.religiousLevel || '',
hasKids: userProfile.hasKids || '',
numberOfKids: userProfile.numberOfKids || 0,
incomeLevel: userProfile.incomeLevel || '',
education: userProfile.education || '',
school: userProfile.school || '',
degree: userProfile.degree || '',
jobTitle: userProfile.jobTitle || '',
company: userProfile.company || '',
industry: userProfile.industry || '',
country: userProfile.country || '',
state: userProfile.state || '',
city: userProfile.city || ''
}
console.log('[ProfileSettings] Setting formData to:', loadedData)
setFormData(loadedData)
}
}, [userProfile])
const handleSave = async () => {
setIsSaving(true)
setSaveMessage('')
try {
// Debug logging to see what we're sending
console.log('[ProfileSettings] Current formData:', formData)
const profileToSave = {
...formData,
email: session?.user?.email,
id: (session?.user as any)?.id || (session as any)?.userId,
name: session?.user?.name,
onboardingCompleted: true,
updatedAt: new Date().toISOString()
}
console.log('[ProfileSettings] Saving profile:', profileToSave)
const response = await fetch('/api/user-profile', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(profileToSave)
})
if (response.ok) {
const result = await response.json()
// Handle both formats: { success: true, profile: {...} } or just {...}
const savedProfile = result.profile || result
onProfileUpdate(savedProfile)
// Also save to localStorage for persistence
localStorage.setItem('userProfile', JSON.stringify(savedProfile))
setSaveMessage('✅ Profile updated successfully!')
setTimeout(() => setSaveMessage(''), 3000)
} else {
setSaveMessage('❌ Failed to update profile')
}
} catch (error) {
console.error('Error saving profile:', error)
setSaveMessage('❌ Error updating profile')
} finally {
setIsSaving(false)
}
}
if (!isOpen) return null
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6 border-b border-gray-200">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-800">Profile Settings</h2>
<button
onClick={onClose}
className="text-gray-500 hover:text-gray-700 text-2xl"
>
×
</button>
</div>
</div>
<div className="p-6 space-y-6">
{/* Basic Info */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-700">Basic Information</h3>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Preferred Name
</label>
<input
type="text"
value={formData.preferredName}
onChange={(e) => setFormData({ ...formData, preferredName: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="What should Bubbe call you?"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Gender
</label>
<select
value={formData.gender}
onChange={(e) => setFormData({ ...formData, gender: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">Select...</option>
<option value="male">Male</option>
<option value="female">Female</option>
<option value="other">Other</option>
<option value="prefer_not">Prefer not to say</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Birth Year
</label>
<input
type="text"
value={formData.birthYear}
onChange={(e) => setFormData({ ...formData, birthYear: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="YYYY"
/>
</div>
</div>
</div>
{/* Relationship & Family */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-700">Relationship & Family</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Relationship Status
</label>
<select
value={formData.relationshipStatus}
onChange={(e) => setFormData({ ...formData, relationshipStatus: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">Select...</option>
<option value="single">Single</option>
<option value="dating">Dating</option>
<option value="engaged">Engaged</option>
<option value="married">Married</option>
<option value="divorced">Divorced</option>
<option value="widowed">Widowed</option>
<option value="complicated">It's complicated</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Have Kids?
</label>
<select
value={formData.hasKids}
onChange={(e) => setFormData({ ...formData, hasKids: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">Select...</option>
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
</div>
{formData.hasKids === 'yes' && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Number of Kids
</label>
<input
type="number"
min="0"
max="20"
value={formData.numberOfKids}
onChange={(e) => setFormData({ ...formData, numberOfKids: parseInt(e.target.value) || 0 })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
/>
</div>
)}
</div>
{/* Career & Education */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-700">Career & Education</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Job Title
</label>
<input
type="text"
value={formData.jobTitle}
onChange={(e) => setFormData({ ...formData, jobTitle: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="Your job title"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Company
</label>
<input
type="text"
value={formData.company}
onChange={(e) => setFormData({ ...formData, company: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="Where you work"
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
School
</label>
<input
type="text"
value={formData.school}
onChange={(e) => setFormData({ ...formData, school: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="Your school"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Degree
</label>
<input
type="text"
value={formData.degree}
onChange={(e) => setFormData({ ...formData, degree: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="Your degree"
/>
</div>
</div>
</div>
{/* Location */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-700">Location</h3>
<div className="grid grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Country
</label>
<input
type="text"
value={formData.country}
onChange={(e) => setFormData({ ...formData, country: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="Country"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
State/Province
</label>
<input
type="text"
value={formData.state}
onChange={(e) => setFormData({ ...formData, state: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="State"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
City
</label>
<input
type="text"
value={formData.city}
onChange={(e) => setFormData({ ...formData, city: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
placeholder="City"
/>
</div>
</div>
</div>
{/* Other */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-700">Other Information</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Religious Level
</label>
<select
value={formData.religiousLevel}
onChange={(e) => setFormData({ ...formData, religiousLevel: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">Select...</option>
<option value="very">Very religious</option>
<option value="somewhat">Somewhat religious</option>
<option value="not_very">Not very religious</option>
<option value="secular">Secular</option>
<option value="atheist">Not religious at all</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Income Level
</label>
<select
value={formData.incomeLevel}
onChange={(e) => setFormData({ ...formData, incomeLevel: e.target.value })}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="">Select...</option>
<option value="under_30k">Under $30,000</option>
<option value="30k_50k">$30,000 - $50,000</option>
<option value="50k_75k">$50,000 - $75,000</option>
<option value="75k_100k">$75,000 - $100,000</option>
<option value="100k_150k">$100,000 - $150,000</option>
<option value="150k_200k">$150,000 - $200,000</option>
<option value="200k_300k">$200,000 - $300,000</option>
<option value="300k_500k">$300,000 - $500,000</option>
<option value="over_500k">Over $500,000</option>
<option value="prefer_not_say">Prefer not to say</option>
</select>
</div>
</div>
</div>
{/* Bubbe Settings */}
<div className="space-y-4 mt-6 pt-6 border-t border-gray-200">
<h3 className="text-lg font-semibold text-gray-700">Bubbe Settings</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Bubbe Personality
</label>
<select
value={typeof window !== 'undefined' ? (localStorage.getItem('bubbePersonality') || 'rude') : 'rude'}
onChange={(e) => {
if (typeof window !== 'undefined') {
localStorage.setItem('bubbePersonality', e.target.value)
setSaveMessage('✅ Personality updated!')
setTimeout(() => setSaveMessage(''), 3000)
}
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="rude">Rude Bubbe (Classic)</option>
<option value="sweet">Sweet Bubbe (Gentle)</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Bubbe Voice
</label>
<select
value={typeof window !== 'undefined' ? (localStorage.getItem('bubbeVoice') || 'yU6e7uJLZCE8eA26VAqb') : 'yU6e7uJLZCE8eA26VAqb'}
onChange={(e) => {
if (typeof window !== 'undefined') {
localStorage.setItem('bubbeVoice', e.target.value)
setSaveMessage('✅ Voice updated!')
setTimeout(() => setSaveMessage(''), 3000)
}
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option value="yU6e7uJLZCE8eA26VAqb">Original Voice</option>
<option value="j9Ic6rh0FeC7nBIqew0q">Softer Voice</option>
<option value="VQHhI9WIBD3z8Ho2ZeUo">Warm Voice</option>
</select>
</div>
</div>
<div className="space-y-2">
<label className="flex items-center space-x-3 cursor-pointer">
<input
type="checkbox"
checked={typeof window !== 'undefined' ? (localStorage.getItem('yiddishEnabled') !== 'false') : true}
onChange={(e) => {
if (typeof window !== 'undefined') {
localStorage.setItem('yiddishEnabled', e.target.checked.toString())
setSaveMessage('✅ Yiddish setting updated!')
setTimeout(() => setSaveMessage(''), 3000)
}
}}
className="w-5 h-5 text-amber-600 rounded focus:ring-amber-500"
/>
<span className="text-gray-700">Use Yiddish expressions (oy vey, meshugana, etc.)</span>
</label>
<label className="flex items-center space-x-3 cursor-pointer">
<input
type="checkbox"
checked={typeof window !== 'undefined' ? (localStorage.getItem('translationEnabled') === 'true') : false}
onChange={(e) => {
if (typeof window !== 'undefined') {
localStorage.setItem('translationEnabled', e.target.checked.toString())
setSaveMessage('✅ Translation setting updated!')
setTimeout(() => setSaveMessage(''), 3000)
}
}}
className="w-5 h-5 text-amber-600 rounded focus:ring-amber-500"
/>
<span className="text-gray-700">Show translations for Yiddish words</span>
</label>
</div>
<div className="mt-4 p-3 bg-amber-50 rounded-lg">
<p className="text-sm text-amber-800">
<strong>Current Settings:</strong><br/>
• Personality: {typeof window !== 'undefined' ? (localStorage.getItem('bubbePersonality') === 'sweet' ? 'Sweet Bubbe' : 'Rude Bubbe') : 'Rude Bubbe'}<br/>
• Voice: {typeof window !== 'undefined' ?
(localStorage.getItem('bubbeVoice') === 'j9Ic6rh0FeC7nBIqew0q' ? 'Softer' :
localStorage.getItem('bubbeVoice') === 'VQHhI9WIBD3z8Ho2ZeUo' ? 'Warm' : 'Original') : 'Original'}<br/>
• Yiddish: {typeof window !== 'undefined' ? (localStorage.getItem('yiddishEnabled') !== 'false' ? 'Enabled' : 'Disabled') : 'Enabled'}<br/>
• Translations: {typeof window !== 'undefined' ? (localStorage.getItem('translationEnabled') === 'true' ? 'Enabled' : 'Disabled') : 'Disabled'}
</p>
</div>
</div>
</div>
<div className="p-6 border-t border-gray-200">
<div className="flex items-center justify-between">
<div className="text-sm">
{saveMessage && (
<span className={saveMessage.includes('✅') ? 'text-green-600' : 'text-red-600'}>
{saveMessage}
</span>
)}
</div>
<div className="space-x-3">
<button
onClick={onClose}
className="px-4 py-2 text-gray-700 bg-gray-200 rounded-lg hover:bg-gray-300"
>
Cancel
</button>
<button
onClick={handleSave}
disabled={isSaving}
className="px-4 py-2 bg-amber-500 text-white rounded-lg hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSaving ? 'Saving...' : 'Save Profile'}
</button>
</div>
</div>
</div>
</div>
</div>
)
}