feat(job-completion): add message and photo upload to job completion
This commit is contained in:
@@ -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}`)
|
||||
|
||||
50
app/actions/upload-image.ts
Normal file
50
app/actions/upload-image.ts
Normal 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}`
|
||||
}
|
||||
Reference in New Issue
Block a user