import { NextRequest, NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { prisma } from '@/lib/prisma'; import bcrypt from 'bcryptjs'; // Get user profile export async function GET(request: NextRequest) { const session = await getServerSession(authOptions); if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const user = await (prisma.user as any).findUnique({ where: { email: session.user.email }, select: { id: true, name: true, email: true, timezone: true, autoRolling: true, protectEventTimes: true, showCalendarProviderIcon: true, language: true, dateFormat: true, timeFormat: true, startHour: true, endHour: true, showNextTask: true, calendarEditMode: true, focusTimerDuration: true, focusBreakDuration: true, showTimeGrid: true, showSomeday: true, showAllDayEvents: true, showSchedule: true, showTaskCheckboxes: true, showProjectIcons: true, showPriorityIcons: true, priorityStyle: true, cellDuration: true, viewStyle: true, viewDays: true, fontSize: true, goalFallbackType: true, goalDefaultSentence: true, goalFontFamily: true, goalFontSize: true, goalFontWeight: true, goalScope: true, dateLayout: true, mobileDateLayout: true, dateVerticalAlign: true, headerDisplay: true, headerCustomFormat: true, headerCurrentDayFormat: true, mobilePortraitHeaderDisplay: true, mobileLandscapeHeaderDisplay: true, headlineFont: true, headlineFontSize: true, headlineFontWeight: true, dateFontFamily: true, dateFontSize: true, dateFontWeight: true, timeTaskFontFamily: true, timeTaskFontSize: true, timeTaskFontWeight: true, bodyFont: true, taskFontFamily: true, taskFontSize: true, taskFontWeight: true, eventFontFamily: true, eventFontSize: true, eventFontWeight: true, fontWeight: true, weekdayColor: true, dateColor: true, taskColor: true, todayHighlightColor: true, weekendColorSat: true, weekendColorSun: true, pastDayColor: true, hourLabelFormat: true, showSubHourSlots: true, allDayPosition: true, cwFontFamily: true, cwFontSize: true, cwFontWeight: true, cwColor: true, yearFontFamily: true, yearFontSize: true, yearFontWeight: true, yearColor: true, dayHeaderGap: true, showCompletedTasks: true, showLines: true, startDayOffset: true, weekdayFormat: true, weekdayCase: true, customWeekdayNames: true, weekStartDay: true, quoteSourceUrls: true, quoteLanguages: true, kanbanStages: true, accountNumber: true, lightTheme: true, darkTheme: true, notificationsEnabled: true, mobileFontScale: true, weatherEnabled: true, weatherLat: true, weatherLon: true, weatherLocation: true, weatherRecentCities: true, viewSettings: true, customCssVars: true, customCss: true, hasCompletedOnboarding: true, createdAt: true } }); if (!user) { return NextResponse.json({ error: 'User not found' }, { status: 404 }); } return NextResponse.json({ user }); } // Update user profile export async function PATCH(request: NextRequest) { const session = await getServerSession(authOptions); if (!session || !session.user?.email) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } try { const body = await request.json(); const { name, timezone, password, autoRolling, protectEventTimes, showCalendarProviderIcon, language, dateFormat, timeFormat, startHour, endHour, showNextTask, calendarEditMode, focusTimerDuration, focusBreakDuration, showTimeGrid, showSomeday, showAllDayEvents, showSchedule, cellDuration, viewStyle, viewDays, fontSize, headlineFont, headlineFontSize, headlineFontWeight, dateFontFamily, dateFontSize, dateFontWeight, timeTaskFontFamily, timeTaskFontSize, timeTaskFontWeight, bodyFont, taskFontFamily, taskFontSize, taskFontWeight, eventFontFamily, eventFontSize, eventFontWeight, fontWeight, weekendColorSat, weekendColorSun, weekdayColor, dateColor, taskColor, todayHighlightColor, pastDayColor, goalFallbackType, goalDefaultSentence, goalFontFamily, goalFontSize, goalFontWeight, goalScope, dateLayout, mobileDateLayout, dateVerticalAlign, headerDisplay, headerCustomFormat, headerCurrentDayFormat, mobilePortraitHeaderDisplay, mobileLandscapeHeaderDisplay, hourLabelFormat, showSubHourSlots, allDayPosition, cwFontFamily, cwFontSize, cwFontWeight, cwColor, yearFontFamily, yearFontSize, yearFontWeight, yearColor, showTaskCheckboxes, showProjectIcons, showPriorityIcons, priorityStyle, dayHeaderGap, showCompletedTasks, showLines, startDayOffset, weekdayFormat, weekdayCase, customWeekdayNames, weekStartDay, quoteSourceUrls, quoteLanguages, kanbanStages, lightTheme, darkTheme, notificationsEnabled, mobileFontScale, weatherEnabled, weatherLat, weatherLon, weatherLocation, weatherRecentCities, viewSettings, customCssVars, customCss, hasCompletedOnboarding } = body; const updateData: any = { ...(name !== undefined && { name }), ...(timezone !== undefined && { timezone }), ...(autoRolling !== undefined && { autoRolling }), ...(protectEventTimes !== undefined && { protectEventTimes }), ...(showCalendarProviderIcon !== undefined && { showCalendarProviderIcon }), ...(language !== undefined && { language }), ...(dateFormat !== undefined && { dateFormat }), ...(timeFormat !== undefined && { timeFormat }), ...(startHour !== undefined && !isNaN(startHour) && { startHour }), ...(endHour !== undefined && !isNaN(endHour) && { endHour }), ...(showNextTask !== undefined && { showNextTask }), ...(calendarEditMode !== undefined && { calendarEditMode }), ...(focusTimerDuration !== undefined && !isNaN(focusTimerDuration) && { focusTimerDuration }), ...(focusBreakDuration !== undefined && !isNaN(focusBreakDuration) && { focusBreakDuration }), ...(showTimeGrid !== undefined && { showTimeGrid }), ...(showSomeday !== undefined && { showSomeday }), ...(showAllDayEvents !== undefined && { showAllDayEvents }), ...(showSchedule !== undefined && { showSchedule }), ...(showTaskCheckboxes !== undefined && { showTaskCheckboxes }), ...(showProjectIcons !== undefined && { showProjectIcons }), ...(showPriorityIcons !== undefined && { showPriorityIcons }), ...(priorityStyle !== undefined && { priorityStyle }), ...(cellDuration !== undefined && !isNaN(cellDuration) && { cellDuration }), ...(viewStyle !== undefined && { viewStyle }), ...(viewDays !== undefined && !isNaN(viewDays) && { viewDays }), ...(fontSize !== undefined && { fontSize }), ...(headlineFont !== undefined && { headlineFont }), ...(headlineFontSize !== undefined && { headlineFontSize }), ...(headlineFontWeight !== undefined && { headlineFontWeight }), ...(dateFontFamily !== undefined && { dateFontFamily }), ...(dateFontSize !== undefined && { dateFontSize }), ...(dateFontWeight !== undefined && { dateFontWeight }), ...(timeTaskFontFamily !== undefined && { timeTaskFontFamily }), ...(timeTaskFontSize !== undefined && { timeTaskFontSize }), ...(timeTaskFontWeight !== undefined && { timeTaskFontWeight }), ...(bodyFont !== undefined && { bodyFont }), ...(taskFontFamily !== undefined && { taskFontFamily }), ...(taskFontSize !== undefined && { taskFontSize }), ...(taskFontWeight !== undefined && { taskFontWeight }), ...(eventFontFamily !== undefined && { eventFontFamily }), ...(eventFontSize !== undefined && { eventFontSize }), ...(eventFontWeight !== undefined && { eventFontWeight }), ...(fontWeight !== undefined && { fontWeight }), ...(weekdayColor !== undefined && { weekdayColor }), ...(dateColor !== undefined && { dateColor }), ...(taskColor !== undefined && { taskColor }), ...(todayHighlightColor !== undefined && { todayHighlightColor }), ...(weekendColorSat !== undefined && { weekendColorSat }), ...(weekendColorSun !== undefined && { weekendColorSun }), ...(pastDayColor !== undefined && { pastDayColor }), ...(goalFallbackType !== undefined && { goalFallbackType }), ...(goalDefaultSentence !== undefined && { goalDefaultSentence }), ...(goalFontFamily !== undefined && { goalFontFamily }), ...(goalFontSize !== undefined && { goalFontSize }), ...(goalFontWeight !== undefined && { goalFontWeight }), ...(goalScope !== undefined && { goalScope }), ...(dateLayout !== undefined && { dateLayout }), ...(mobileDateLayout !== undefined && { mobileDateLayout }), ...(dateVerticalAlign !== undefined && { dateVerticalAlign }), ...(headerDisplay !== undefined && { headerDisplay }), ...(headerCustomFormat !== undefined && { headerCustomFormat }), ...(headerCurrentDayFormat !== undefined && { headerCurrentDayFormat }), ...(mobilePortraitHeaderDisplay !== undefined && { mobilePortraitHeaderDisplay }), ...(mobileLandscapeHeaderDisplay !== undefined && { mobileLandscapeHeaderDisplay }), ...(hourLabelFormat !== undefined && { hourLabelFormat }), ...(showSubHourSlots !== undefined && { showSubHourSlots }), ...(allDayPosition !== undefined && { allDayPosition }), ...(cwFontFamily !== undefined && { cwFontFamily }), ...(cwFontSize !== undefined && { cwFontSize }), ...(cwFontWeight !== undefined && { cwFontWeight }), ...(cwColor !== undefined && { cwColor }), ...(yearFontFamily !== undefined && { yearFontFamily }), ...(yearFontSize !== undefined && { yearFontSize }), ...(yearFontWeight !== undefined && { yearFontWeight }), ...(yearColor !== undefined && { yearColor }), ...(dayHeaderGap !== undefined && { dayHeaderGap }), ...(showCompletedTasks !== undefined && { showCompletedTasks }), ...(showLines !== undefined && { showLines }), ...(startDayOffset !== undefined && { startDayOffset }), ...(weekdayFormat !== undefined && { weekdayFormat }), ...(weekdayCase !== undefined && { weekdayCase }), ...(customWeekdayNames !== undefined && { customWeekdayNames }), ...(weekStartDay !== undefined && { weekStartDay }), ...(quoteSourceUrls !== undefined && { quoteSourceUrls }), ...(quoteLanguages !== undefined && { quoteLanguages }), ...(kanbanStages !== undefined && { kanbanStages }), ...(lightTheme !== undefined && { lightTheme }), ...(darkTheme !== undefined && { darkTheme }), ...(notificationsEnabled !== undefined && { notificationsEnabled }), ...(mobileFontScale !== undefined && { mobileFontScale: parseFloat(mobileFontScale) || 1.0 }), ...(weatherEnabled !== undefined && { weatherEnabled }), ...(weatherLat !== undefined && { weatherLat: weatherLat !== null ? parseFloat(weatherLat) : null }), ...(weatherLon !== undefined && { weatherLon: weatherLon !== null ? parseFloat(weatherLon) : null }), ...(weatherLocation !== undefined && { weatherLocation }), ...(weatherRecentCities !== undefined && { weatherRecentCities }), ...(viewSettings !== undefined && { viewSettings }), ...(customCssVars !== undefined && { customCssVars }), ...(customCss !== undefined && { customCss }), ...(hasCompletedOnboarding !== undefined && { hasCompletedOnboarding }), }; if (password && password.trim() !== "") { updateData.passwordHash = await bcrypt.hash(password, 10); } const user = await (prisma.user as any).update({ where: { email: session.user.email }, data: updateData, select: { id: true, name: true, email: true, timezone: true, autoRolling: true, protectEventTimes: true, language: true, dateFormat: true, timeFormat: true, startHour: true, endHour: true, showNextTask: true, calendarEditMode: true, focusTimerDuration: true, focusBreakDuration: true, showTimeGrid: true, showSomeday: true, showAllDayEvents: true, showSchedule: true, showTaskCheckboxes: true, showProjectIcons: true, showPriorityIcons: true, priorityStyle: true, cellDuration: true, viewStyle: true, viewDays: true, fontSize: true, headlineFont: true, headlineFontSize: true, headlineFontWeight: true, dateFontFamily: true, dateFontSize: true, dateFontWeight: true, timeTaskFontFamily: true, timeTaskFontSize: true, timeTaskFontWeight: true, bodyFont: true, taskFontFamily: true, taskFontSize: true, taskFontWeight: true, eventFontFamily: true, eventFontSize: true, eventFontWeight: true, fontWeight: true, weekdayColor: true, dateColor: true, taskColor: true, todayHighlightColor: true, weekendColorSat: true, weekendColorSun: true, pastDayColor: true, hourLabelFormat: true, showSubHourSlots: true, allDayPosition: true, goalFallbackType: true, goalDefaultSentence: true, goalFontFamily: true, goalFontSize: true, goalFontWeight: true, goalScope: true, dateLayout: true, mobileDateLayout: true, dateVerticalAlign: true, headerDisplay: true, headerCustomFormat: true, headerCurrentDayFormat: true, mobilePortraitHeaderDisplay: true, mobileLandscapeHeaderDisplay: true, cwFontFamily: true, cwFontSize: true, cwFontWeight: true, cwColor: true, yearFontFamily: true, yearFontSize: true, yearFontWeight: true, yearColor: true, dayHeaderGap: true, showCompletedTasks: true, showLines: true, startDayOffset: true, weekdayFormat: true, weekdayCase: true, customWeekdayNames: true, weekStartDay: true, quoteSourceUrls: true, quoteLanguages: true, kanbanStages: true, accountNumber: true, lightTheme: true, darkTheme: true, notificationsEnabled: true, mobileFontScale: true, weatherEnabled: true, weatherLat: true, weatherLon: true, weatherLocation: true, weatherRecentCities: true, viewSettings: true, customCssVars: true, customCss: true, hasCompletedOnboarding: true, } }); return NextResponse.json({ success: true, user }); } catch (e) { console.error('Error updating profile:', e); return NextResponse.json( { error: 'Failed to update profile', details: (e as Error).message }, { status: 500 } ); } } // Delete account export async function DELETE(request: NextRequest) { const session = await getServerSession(authOptions); if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); try { await prisma.user.delete({ where: { email: session.user.email } }); return NextResponse.json({ success: true }); } catch (error) { console.error('Error deleting account:', error); return NextResponse.json({ error: 'Failed to delete account' }, { status: 500 }); } }