feat(job-completion): add message and photo upload to job completion

This commit is contained in:
2026-01-13 11:41:21 +01:00
parent e104a9d377
commit 97d8f12fc0
14 changed files with 265 additions and 25 deletions

View File

@@ -83,7 +83,7 @@ export async function deleteBooking(bookingId: number, planId: string, lang: str
revalidatePath(`/${lang}/dashboard/${planId}`)
}
export async function completeBooking(bookingId: number, planId: string, lang: string = "en") {
export async function completeBooking(bookingId: number, planId: string, lang: string = "en", message?: string, imageUrl?: string) {
const dict = await getDictionary(lang as any)
const booking = await prisma.booking.findUnique({
@@ -95,7 +95,11 @@ export async function completeBooking(bookingId: number, planId: string, lang: s
await prisma.booking.update({
where: { id: bookingId },
data: { completedAt: new Date() }
data: {
completedAt: new Date(),
completionMessage: message,
completionImage: imageUrl
}
})
if (booking.plan.notifyAll) {
@@ -104,12 +108,19 @@ export async function completeBooking(bookingId: number, planId: string, lang: s
const planUrl = `${protocol}://${host}/${lang}/dashboard/${planId}`
const dateStr = booking.date.toLocaleDateString(lang)
const message = dict.notifications.completed
let notificationMessage = dict.notifications.completed
.replace("{name}", booking.sitterName || "Someone")
.replace("{date}", dateStr)
.replace("{url}", planUrl)
await sendPlanNotification(planId, message, booking.plan.webhookUrl)
if (message) {
notificationMessage += `\n"${message}"`
}
// We need to pass the full URL for the image
const fullImageUrl = imageUrl ? `${protocol}://${host}${imageUrl}` : undefined
await sendPlanNotification(planId, notificationMessage, booking.plan.webhookUrl, fullImageUrl)
}
revalidatePath(`/${lang}/dashboard/${planId}`)

View File

@@ -0,0 +1,50 @@
"use server"
import { writeFile, mkdir } from "fs/promises"
import { join } from "path"
import { v4 as uuidv4 } from "uuid"
export async function uploadImage(data: FormData) {
const file: File | null = data.get("file") as unknown as File
if (!file) {
throw new Error("No file uploaded")
}
const bytes = await file.arrayBuffer()
const buffer = Buffer.from(bytes)
// Validate mime type (basic check)
if (!file.type.startsWith("image/")) {
throw new Error("Only images are allowed")
}
// Create uploads directory if it doesn't exist
// We organize by generic uploads folder for now, or per plan?
// Let's optimize for simplicity: /public/uploads/YYYY/MM
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const params = data.get("planId") ? String(data.get("planId")) : "misc"
// Use /uploads/planId/ to keep it somewhat organized or cleanup-able
const relativeDir = join("uploads", params)
const uploadDir = join(process.cwd(), "public", relativeDir)
try {
await mkdir(uploadDir, { recursive: true })
} catch (e) {
// ignore if exists
}
// Generate filename
const ext = file.name.split('.').pop() || "jpg"
const filename = `${uuidv4()}.${ext}`
const filepath = join(uploadDir, filename)
await writeFile(filepath, buffer)
// Return the public URL
return `/${relativeDir}/${filename}`
}