hensei-web/app/api/auth/login/route.ts
Justin Edmund e4b7f0c356
Fix TypeScript errors for production build (#436)
## Summary
Fixed multiple TypeScript errors that were preventing the production
build from completing on Railway.

## Changes Made

### Nullable Type Fixes
- Fixed `searchParams.toString()` calls with optional chaining (`?.`)
and fallback values
- Fixed `pathname` nullable access in UpdateToastClient
- Added fallbacks for undefined values in translation interpolations

### Type Consistency Fixes
- Fixed recency parameter handling (string from URL, converted to number
internally)
- Removed duplicate local interface definitions for Party and User types
- Fixed Party type mismatches by using global type definitions

### API Route Error Handling
- Fixed error type checking in catch blocks for login/signup routes
- Added proper type guards for axios error objects

### Component Props Fixes
- Fixed RadixSelect.Trigger by removing invalid placeholder prop
- Fixed Toast and Tooltip components by using Omit to exclude
conflicting content type
- Added missing onAdvancedFilter prop to FilterBar components
- Fixed PartyFooter props with required parameters

## Test Plan
- [x] Fixed all TypeScript compilation errors locally
- [ ] Production build should complete successfully on Railway
- [ ] All affected components should function correctly

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 01:47:10 -07:00

103 lines
No EOL
2.8 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { cookies } from 'next/headers'
import { login as loginHelper } from '~/app/lib/api-utils'
// Login request schema
const LoginSchema = z.object({
email: z.string().email('Invalid email format'),
password: z.string().min(8, 'Password must be at least 8 characters')
})
export async function POST(request: NextRequest) {
try {
// Parse and validate request body
const body = await request.json()
const validatedData = LoginSchema.parse(body)
// Call login helper with credentials
const response = await loginHelper(validatedData)
// Set cookies based on response
if (response.token) {
// Calculate expiration (60 days)
const expiresAt = new Date()
expiresAt.setDate(expiresAt.getDate() + 60)
// Set account cookie with auth info
const accountCookie = {
userId: response.user_id,
username: response.username,
role: response.role,
token: response.token
}
// Set user cookie with preferences/profile
const userCookie = {
avatar: {
picture: response.avatar.picture,
element: response.avatar.element
},
gender: response.gender,
language: response.language,
theme: response.theme,
bahamut: response.bahamut || false
}
// Set cookies
const cookieStore = cookies()
cookieStore.set('account', JSON.stringify(accountCookie), {
expires: expiresAt,
path: '/',
httpOnly: true,
sameSite: 'strict'
})
cookieStore.set('user', JSON.stringify(userCookie), {
expires: expiresAt,
path: '/',
httpOnly: true,
sameSite: 'strict'
})
// Return success
return NextResponse.json({
success: true,
user: {
username: response.username,
avatar: response.avatar
}
})
}
// If we get here, something went wrong
return NextResponse.json(
{ error: 'Invalid login response' },
{ status: 500 }
)
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation error', details: error.errors },
{ status: 400 }
)
}
// For authentication errors
if (error && typeof error === 'object' && 'response' in error) {
const axiosError = error as any
if (axiosError.response?.status === 401) {
return NextResponse.json(
{ error: 'Invalid email or password' },
{ status: 401 }
)
}
}
console.error('Login error:', error)
return NextResponse.json(
{ error: 'Login failed' },
{ status: 500 }
)
}
}