51 lines
1.8 KiB
TypeScript
51 lines
1.8 KiB
TypeScript
import prisma from "@/lib/prisma"
|
|
import { NextResponse } from "next/server"
|
|
|
|
export async function GET(
|
|
request: Request,
|
|
{ params }: { params: Promise<{ planId: string }> }
|
|
) {
|
|
const { planId } = await params
|
|
const plan = await prisma.plan.findUnique({
|
|
where: { id: planId },
|
|
include: { bookings: true }
|
|
})
|
|
|
|
if (!plan) {
|
|
return new NextResponse("Plan not found", { status: 404 })
|
|
}
|
|
|
|
let icsContent = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Cat Sitting Planner//EN\n"
|
|
|
|
for (const booking of plan.bookings) {
|
|
if (booking.type === "OWNER_HOME") continue; // Don't put owner home days in calendar? Or maybe do?
|
|
|
|
const date = new Date(booking.date)
|
|
const dateStr = date.toISOString().replace(/-|:|\.\d\d\d/g, "").slice(0, 8)
|
|
|
|
icsContent += "BEGIN:VEVENT\n"
|
|
icsContent += `DTSTART;VALUE=DATE:${dateStr}\n`
|
|
icsContent += `DTEND;VALUE=DATE:${dateStr}\n` // Single day event usually ends next day or same day? Calendar usually expects Start and End. For all day: DTSTART:YYYYMMDD, DTEND:YYYYMMDD+1
|
|
|
|
// Calculate next day for DTEND
|
|
const nextDate = new Date(date)
|
|
nextDate.setDate(date.getDate() + 1)
|
|
const nextDateStr = nextDate.toISOString().replace(/-|:|\.\d\d\d/g, "").slice(0, 8)
|
|
|
|
icsContent = icsContent.replace(`DTEND;VALUE=DATE:${dateStr}\n`, `DTEND;VALUE=DATE:${nextDateStr}\n`)
|
|
|
|
icsContent += `SUMMARY:Cat Sitting: ${booking.sitterName}\n`
|
|
icsContent += `DESCRIPTION:Cat sitting for plan ${plan.id}\n`
|
|
icsContent += "END:VEVENT\n"
|
|
}
|
|
|
|
icsContent += "END:VCALENDAR"
|
|
|
|
return new NextResponse(icsContent, {
|
|
headers: {
|
|
"Content-Type": "text/calendar",
|
|
"Content-Disposition": `attachment; filename="cat-sitting-${plan.startDate.toISOString().slice(0, 10)}.ics"`
|
|
}
|
|
})
|
|
}
|