import { NextRequest, NextResponse } from 'next/server' import { prisma } from '@/lib/db/prisma' import { getCurrentUser } from '@/lib/auth' import { canAccessWorkspace } from '@/lib/db/workspace-access' import { format, addDays } from 'date-fns' // GET /api/workspaces/[id]/calendar-feed export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { try { const workspaceId = params.id const token = request.nextUrl.searchParams.get('token') if (!token) { return NextResponse.json({ error: 'Missing token' }, { status: 401 }) } // Find the calendar feed const feed = await prisma.calendarFeed.findUnique({ where: { token } }) if (!feed || feed.workspaceId !== workspaceId) { return NextResponse.json({ error: 'Invalid token' }, { status: 401 }) } // Update last accessed await prisma.calendarFeed.update({ where: { id: feed.id }, data: { lastAccessedAt: new Date() } }) // Fetch appointments const appointments = await prisma.appointment.findMany({ where: { workspaceId, deletedAt: null, datetime: { gte: new Date(), lte: addDays(new Date(), feed.daysAhead) } }, orderBy: { datetime: 'asc' } }) // Generate ICS content const icsContent = generateICS(appointments, feed.includeMeds) // Return as ICS file return new NextResponse(icsContent, { headers: { 'Content-Type': 'text/calendar; charset=utf-8', 'Content-Disposition': `attachment; filename="nextstep-calendar-${workspaceId}.ics"`, }, }) } catch (error) { console.error('Failed to generate calendar feed:', error) return NextResponse.json( { error: 'Failed to generate calendar feed' }, { status: 500 } ) } } function generateICS(appointments: any[], includeMeds: boolean): string { const events = appointments.map(appt => { const start = new Date(appt.datetime) const end = new Date(start.getTime() + 60 * 60 * 1000) // 1 hour default return ` BEGIN:VEVENT UID:${appt.id}@nextstep.app DTSTART:${format(start, "yyyyMMdd'T'HHmmss")} DTEND:${format(end, "yyyyMMdd'T'HHmmss")} SUMMARY:${escapeICS(appt.title)} ${appt.location ? `LOCATION:${escapeICS(appt.location)}` : ''} ${appt.notes ? `DESCRIPTION:${escapeICS(appt.notes)}` : ''} STATUS:CONFIRMED END:VEVENT` }).join('') return `BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Next Step//Calendar//EN CALSCALE:GREGORIAN METHOD:PUBLISH X-WR-CALNAME:Next Step Appointments X-WR-TIMEZONE:Australia/Perth ${events} END:VCALENDAR` } function escapeICS(str: string): string { return str .replace(/\\/g, '\\\\') .replace(/;/g, '\\;') .replace(/,/g, '\\,') .replace(/\n/g, '\\n') }