← back to Dear Bubbe Nextjs
app/api/user-profile/route.ts
228 lines
import { NextRequest, NextResponse } from 'next/server'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import fs from 'fs/promises'
import path from 'path'
// Simple file-based storage for user profiles
const PROFILES_DIR = path.join(process.cwd(), 'data', 'profiles')
// Ensure profiles directory exists
async function ensureProfilesDir() {
try {
await fs.mkdir(PROFILES_DIR, { recursive: true })
} catch (error) {
console.error('Failed to create profiles directory:', error)
}
}
export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.email) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })
}
await ensureProfilesDir()
// Use email as unique identifier
const profileFile = path.join(PROFILES_DIR, `${session.user.email}.json`)
try {
const profileData = await fs.readFile(profileFile, 'utf-8')
return NextResponse.json(JSON.parse(profileData))
} catch (error) {
// Profile doesn't exist yet
return NextResponse.json({ onboardingCompleted: false })
}
} catch (error) {
console.error('Error fetching profile:', error)
return NextResponse.json({ error: 'Failed to fetch profile' }, { status: 500 })
}
}
export async function POST(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.email) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })
}
const data = await request.json()
await ensureProfilesDir()
// Check if profile already exists
const profileFile = path.join(PROFILES_DIR, `${session.user.email}.json`)
let existingProfile: any = {}
let isExistingProfile = false
try {
const profileData = await fs.readFile(profileFile, 'utf-8')
existingProfile = JSON.parse(profileData)
isExistingProfile = true
console.log(`[PROFILE] Found existing profile:`, existingProfile)
} catch (error) {
console.log(`[PROFILE] No existing profile found, creating new one`)
}
// Smart merge: For each field, use new value if provided, otherwise keep existing
const profileFields = [
'preferredName', 'gender', 'relationshipStatus', 'birthYear',
'religiousLevel', 'hasKids', 'numberOfKids', 'incomeLevel',
'education', 'school', 'degree', 'jobTitle', 'company',
'industry', 'country', 'state', 'city'
]
const mergedData: any = {}
// For each field, decide whether to use new or existing value
for (const field of profileFields) {
if (field in data) {
// If the field is explicitly set in the new data
// Keep the value even if it's empty (user might want to clear it)
// But if it's the initial save and all fields are empty, use existing
const allFieldsEmpty = profileFields.every(f => !data[f] || data[f] === '')
if (allFieldsEmpty && isExistingProfile) {
// This is likely the initial form load with empty data, preserve existing
mergedData[field] = existingProfile[field] || data[field]
} else {
// User actually edited the form, use their value
mergedData[field] = data[field]
}
} else if (existingProfile && field in existingProfile) {
// Field not in new data, keep existing
mergedData[field] = existingProfile[field]
}
}
console.log(`[PROFILE] Merged data:`, mergedData)
// Build the final profile
const profile = {
...mergedData,
id: (session.user as any).id || session.user.email,
email: session.user.email,
name: session.user.name,
onboardingCompleted: true,
updatedAt: new Date().toISOString(),
createdAt: isExistingProfile ? existingProfile.createdAt : new Date().toISOString()
}
// Save profile to file (profileFile already declared above)
await fs.writeFile(profileFile, JSON.stringify(profile, null, 2))
console.log(`[PROFILE] Saved profile for ${session.user.email}:`, profile)
// Return the profile directly for consistency
return NextResponse.json(profile)
} catch (error) {
console.error('Error saving profile:', error)
return NextResponse.json({ error: 'Failed to save profile' }, { status: 500 })
}
}
export async function PUT(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.email) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })
}
const updates = await request.json()
await ensureProfilesDir()
const profileFile = path.join(PROFILES_DIR, `${session.user.email}.json`)
// Read existing profile
let existingProfile = {}
try {
const profileData = await fs.readFile(profileFile, 'utf-8')
existingProfile = JSON.parse(profileData)
} catch (error) {
// Profile doesn't exist, create new one
}
const profile = {
...existingProfile,
...updates,
email: session.user.email,
name: session.user.name,
updatedAt: new Date().toISOString()
}
await fs.writeFile(profileFile, JSON.stringify(profile, null, 2))
console.log(`[PROFILE] Updated profile for ${session.user.email}:`, profile)
// Return the profile directly for consistency
return NextResponse.json(profile)
} catch (error) {
console.error('Error updating profile:', error)
return NextResponse.json({ error: 'Failed to update profile' }, { status: 500 })
}
}
export async function DELETE(request: NextRequest) {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.email) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })
}
const { email } = await request.json()
// Verify the user is deleting their own account
if (email !== session.user.email) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 403 })
}
await ensureProfilesDir()
// Delete profile file
const profileFile = path.join(PROFILES_DIR, `${email}.json`)
try {
await fs.unlink(profileFile)
console.log(`[PROFILE] Deleted profile for ${email}`)
} catch (error) {
console.log(`[PROFILE] Profile file not found for ${email}`)
}
// Delete memory file
const memoriesDir = path.join(process.cwd(), 'user-memories')
const userId = (session.user as any).id || email.replace('@', '_').replace('.', '_')
const memoryFile = path.join(memoriesDir, `${userId}.md`)
try {
await fs.unlink(memoryFile)
console.log(`[PROFILE] Deleted memory file for ${userId}`)
} catch (error) {
console.log(`[PROFILE] Memory file not found for ${userId}`)
}
// Delete any conversation history files
const conversationsDir = path.join(process.cwd(), 'data', 'conversations')
const conversationFile = path.join(conversationsDir, `${email}.json`)
try {
await fs.unlink(conversationFile)
console.log(`[PROFILE] Deleted conversation history for ${email}`)
} catch (error) {
console.log(`[PROFILE] Conversation file not found for ${email}`)
}
return NextResponse.json({
success: true,
message: 'Account and all associated data deleted successfully'
})
} catch (error) {
console.error('Error deleting profile:', error)
return NextResponse.json({ error: 'Failed to delete profile' }, { status: 500 })
}
}