Skip to content

Commit 6953e7d

Browse files
committed
Initial attempt
1 parent dd88ee5 commit 6953e7d

File tree

4 files changed

+105
-60
lines changed

4 files changed

+105
-60
lines changed

app/api/getAbsences/route.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export interface AbsenceWithRelations {
2626
};
2727
}
2828

29-
export async function GET() {
29+
export const searchAbsences = async (): Promise<AbsenceWithRelations[]> => {
3030
try {
3131
const absences: AbsenceWithRelations[] = await prisma.absence.findMany({
3232
select: {
@@ -63,6 +63,17 @@ export async function GET() {
6363
},
6464
});
6565

66+
return absences;
67+
} catch (err) {
68+
console.error('Error fetching absences:', err);
69+
throw err;
70+
}
71+
};
72+
73+
export async function GET() {
74+
try {
75+
const absences = await searchAbsences();
76+
6677
if (!absences.length) {
6778
return NextResponse.json({ events: [] }, { status: 200 });
6879
}

app/api/ics/[id]/ics.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { EventAttributes, createEvents } from 'ics';
2+
import { AbsenceWithRelations } from '../../getAbsences/route';
3+
import { searchAbsences } from '../../getAbsences/route';
4+
5+
export const getAbsenceEvents = async (): Promise<EventAttributes[]> => {
6+
try {
7+
const absences = await searchAbsences();
8+
9+
return absences.map((absence: AbsenceWithRelations) => {
10+
const substituteTeacherString = absence.substituteTeacher
11+
? `(${absence.substituteTeacher.firstName} ${absence.substituteTeacher.lastName[0]})`
12+
: '';
13+
const lessonString = absence.lessonPlan || 'Lesson Plan Not Submitted';
14+
const notesLine = absence.notes ? `\nNotes: ${absence.notes}` : '';
15+
16+
const startDate = new Date(absence.lessonDate);
17+
const endDate = new Date(absence.lessonDate);
18+
endDate.setDate(startDate.getDate() + 1);
19+
20+
return {
21+
start: [
22+
startDate.getFullYear(),
23+
startDate.getMonth() + 1,
24+
startDate.getDate(),
25+
],
26+
end: [endDate.getFullYear(), endDate.getMonth() + 1, endDate.getDate()],
27+
title: `${absence.subject.name}: ${absence.absentTeacher.firstName} ${absence.absentTeacher.lastName[0]}${substituteTeacherString}`,
28+
description: `Subject: ${absence.subject.name}\nLesson Plan: ${lessonString}${notesLine}`,
29+
location: absence.location.name,
30+
};
31+
});
32+
} catch (err) {
33+
console.error('Error fetching absences:', err);
34+
throw err;
35+
}
36+
};
37+
38+
export const createCalendarFile = (
39+
events: EventAttributes[]
40+
): Promise<File> => {
41+
return new Promise((resolve, reject) => {
42+
createEvents(events, (error, value) => {
43+
if (error) {
44+
console.error('Error creating events:', error);
45+
reject(error);
46+
} else {
47+
resolve(new File([value], 'Absences.ics', { type: 'text/calendar' }));
48+
}
49+
});
50+
});
51+
};

app/api/ics/[id]/route.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
import { getAbsenceEvents, createCalendarFile } from './ics';
3+
4+
const getICSFileById = async (id: string) => {
5+
console.log('Getting ICS file for id:', id);
6+
let events = await getAbsenceEvents();
7+
return createCalendarFile(events);
8+
};
9+
10+
export async function GET(
11+
req: NextRequest,
12+
{ params }: { params: { id: string } }
13+
) {
14+
const { id } = params;
15+
console.log('ICS file requested:', id);
16+
17+
if (!id || typeof id !== 'string') {
18+
return NextResponse.json({ error: 'Invalid request' }, { status: 400 });
19+
}
20+
21+
try {
22+
const icsFile = await getICSFileById(id);
23+
if (!icsFile) {
24+
return NextResponse.json({ error: 'File not found' }, { status: 404 });
25+
}
26+
27+
return new Response(icsFile, {
28+
headers: { 'Content-Type': 'text/calendar' },
29+
});
30+
} catch (error) {
31+
console.error('Error fetching ICS file:', error);
32+
return NextResponse.json(
33+
{ error: 'Internal server error' },
34+
{ status: 500 }
35+
);
36+
}
37+
}

src/pages/ics.tsx

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,12 @@
1-
import { EventAttributes, createEvents } from 'ics';
21
import React, { useState } from 'react';
3-
import { AbsenceWithRelations } from '../../app/api/getAbsences/route';
2+
import {
3+
getAbsenceEvents,
4+
createCalendarFile,
5+
} from '../../app/api/ics/[id]/ics';
46

57
export default function CalendarDownload() {
68
const [error, setError] = useState<string | null>(null);
79

8-
const searchAbsences = async (): Promise<EventAttributes[]> => {
9-
try {
10-
const res = await fetch('/api/getAbsences/');
11-
if (!res.ok) {
12-
throw new Error(`Failed to fetch: ${res.statusText}`);
13-
}
14-
const data = await res.json();
15-
if (!data.events || !Array.isArray(data.events)) {
16-
throw new Error('Invalid data format.');
17-
}
18-
return data.events.map((absence: AbsenceWithRelations) => {
19-
const substituteTeacherString = absence.substituteTeacher
20-
? `(${absence.substituteTeacher.firstName} ${absence.substituteTeacher.lastName[0]})`
21-
: '';
22-
const lessonString = absence.lessonPlan || 'Lesson Plan Not Submitted';
23-
const notesLine = absence.notes ? `\nNotes: ${absence.notes}` : '';
24-
25-
const startDate = new Date(absence.lessonDate);
26-
const endDate = new Date(absence.lessonDate);
27-
endDate.setDate(startDate.getDate() + 1);
28-
29-
return {
30-
start: [
31-
startDate.getFullYear(),
32-
startDate.getMonth() + 1,
33-
startDate.getDate(),
34-
],
35-
end: [
36-
endDate.getFullYear(),
37-
endDate.getMonth() + 1,
38-
endDate.getDate(),
39-
],
40-
title: `${absence.subject.name}: ${absence.absentTeacher.firstName} ${absence.absentTeacher.lastName[0]}${substituteTeacherString}`,
41-
description: `Subject: ${absence.subject.name}\nLesson Plan: ${lessonString}${notesLine}`,
42-
location: absence.location.name,
43-
};
44-
});
45-
} catch (err) {
46-
console.error('Error fetching absences:', err);
47-
throw err;
48-
}
49-
};
50-
51-
const createCalendarFile = (events: EventAttributes[]): Promise<File> => {
52-
return new Promise((resolve, reject) => {
53-
createEvents(events, (error, value) => {
54-
if (error) {
55-
console.error('Error creating events:', error);
56-
reject(error);
57-
} else {
58-
resolve(new File([value], 'Absences.ics', { type: 'text/calendar' }));
59-
}
60-
});
61-
});
62-
};
63-
6410
const downloadFile = (file: File) => {
6511
const url = URL.createObjectURL(file);
6612
const anchor = document.createElement('a');
@@ -77,7 +23,7 @@ export default function CalendarDownload() {
7723
setError(null);
7824

7925
try {
80-
const events = await searchAbsences();
26+
const events = await getAbsenceEvents();
8127
const file = await createCalendarFile(events);
8228
downloadFile(file);
8329
} catch (error) {

0 commit comments

Comments
 (0)