Production Deployment Fixes and Enhancements #3

Merged
ilia merged 38 commits from dev into main 2026-01-04 16:37:35 -05:00
4 changed files with 25 additions and 16 deletions
Showing only changes of commit 90c5a9a4df - Show all commits

View File

@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server"
import { auth } from "@/lib/auth"
import { prisma } from "@/lib/prisma"
import { sendNewPhotoEmail } from "@/lib/email"
import type { Prisma } from "@prisma/client"
// Legacy endpoint for URL-based uploads (kept for backward compatibility)
export async function POST(req: NextRequest) {
@ -46,7 +47,7 @@ export async function POST(req: NextRequest) {
answerName: answerName.trim(),
points: pointsValue,
maxAttempts: maxAttemptsValue,
} as any,
} as Prisma.PhotoUncheckedCreateInput,
include: {
uploader: {
select: {

View File

@ -6,7 +6,7 @@ import { writeFile } from "fs/promises"
import { join } from "path"
import { existsSync, mkdirSync } from "fs"
import { createHash } from "crypto"
import type { Photo } from "@prisma/client"
import type { Prisma } from "@prisma/client"
export async function POST(req: NextRequest) {
try {
@ -44,9 +44,9 @@ export async function POST(req: NextRequest) {
mkdirSync(uploadsDir, { recursive: true })
}
type PhotoWithUploader = Photo & {
uploader: { name: string }
}
type PhotoWithUploader = Prisma.PhotoGetPayload<{
include: { uploader: { select: { name: true } } }
}>
const createdPhotos: PhotoWithUploader[] = []
@ -106,7 +106,7 @@ export async function POST(req: NextRequest) {
// Check for duplicate file
const existingPhoto = await prisma.photo.findFirst({
where: { fileHash } as any,
where: { fileHash } as Prisma.PhotoWhereInput,
})
if (existingPhoto) {
@ -158,7 +158,7 @@ export async function POST(req: NextRequest) {
penaltyEnabled: penaltyEnabled,
penaltyPoints: penaltyPointsValue,
maxAttempts: maxAttemptsValue,
} as any,
} as Prisma.PhotoUncheckedCreateInput,
include: {
uploader: {
select: {
@ -168,7 +168,7 @@ export async function POST(req: NextRequest) {
},
})
createdPhotos.push(photo as PhotoWithUploader)
createdPhotos.push(photo)
}
// Send emails to all other users for all photos

View File

@ -6,6 +6,7 @@ import { writeFile } from "fs/promises"
import { join } from "path"
import { existsSync, mkdirSync } from "fs"
import { createHash } from "crypto"
import type { Prisma } from "@prisma/client"
export async function POST(req: NextRequest) {
try {
@ -62,7 +63,7 @@ export async function POST(req: NextRequest) {
// Check for duplicate file
const existingPhoto = await prisma.photo.findFirst({
where: { fileHash } as any,
where: { fileHash } as Prisma.PhotoWhereInput,
})
if (existingPhoto) {
@ -122,7 +123,7 @@ export async function POST(req: NextRequest) {
answerName: answerName.trim(),
points: pointsValue,
maxAttempts: maxAttemptsValue,
} as any,
} as Prisma.PhotoUncheckedCreateInput,
include: {
uploader: {
select: {

View File

@ -49,10 +49,17 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
const hasCorrectGuess = userGuess?.correct || false
const isOwner = photo.uploaderId === session.user.id
// Type assertion for new fields (penaltyEnabled, penaltyPoints, maxAttempts)
type PhotoWithNewFields = typeof photo & {
penaltyEnabled: boolean
penaltyPoints: number
maxAttempts: number | null
}
const photoWithFields = photo as PhotoWithNewFields
// Calculate remaining attempts
const photoWithMaxAttempts = photo as typeof photo & { maxAttempts: number | null | undefined }
const userGuessCount = photo.guesses.length
const maxAttempts = photoWithMaxAttempts.maxAttempts ?? null
const maxAttempts = photoWithFields.maxAttempts ?? null
const remainingAttempts = maxAttempts !== null && maxAttempts > 0
? Math.max(0, maxAttempts - userGuessCount)
: null
@ -77,9 +84,9 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-purple-100 text-purple-800">
+{photo.points} {photo.points === 1 ? "point" : "points"} if correct
</span>
{(photo as any).penaltyEnabled && (photo as any).penaltyPoints > 0 && (
{photoWithFields.penaltyEnabled && photoWithFields.penaltyPoints > 0 && (
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800">
-{(photo as any).penaltyPoints} {(photo as any).penaltyPoints === 1 ? "point" : "points"} if wrong
-{photoWithFields.penaltyPoints} {photoWithFields.penaltyPoints === 1 ? "point" : "points"} if wrong
</span>
)}
{maxAttempts !== null && maxAttempts > 0 && (
@ -117,9 +124,9 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
<p className="text-sm text-red-700 mt-1">
Your last guess: <strong>{userGuess.guessText}</strong>
</p>
{(photo as any).penaltyEnabled && (photo as any).penaltyPoints > 0 && (
{photoWithFields.penaltyEnabled && photoWithFields.penaltyPoints > 0 && (
<p className="text-sm text-red-700 mt-1">
You lost <strong>{(photo as any).penaltyPoints} {(photo as any).penaltyPoints === 1 ? "point" : "points"}</strong> for this wrong guess.
You lost <strong>{photoWithFields.penaltyPoints} {photoWithFields.penaltyPoints === 1 ? "point" : "points"}</strong> for this wrong guess.
</p>
)}
</div>