Skip to content

Commit 5ef0bfa

Browse files
committed
Refactor event functions
1 parent c45c605 commit 5ef0bfa

File tree

5 files changed

+139
-120
lines changed

5 files changed

+139
-120
lines changed

app/api/getAbsences/absences.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { prisma } from '@utils/prisma';
2+
3+
export interface AbsenceWithRelations {
4+
lessonDate: Date;
5+
lessonPlan: string | null;
6+
reasonOfAbsence: string;
7+
notes: string | null;
8+
absentTeacher: {
9+
firstName: string;
10+
lastName: string;
11+
email: string;
12+
};
13+
substituteTeacher: {
14+
firstName: string;
15+
lastName: string;
16+
email: string;
17+
} | null;
18+
location: {
19+
name: string;
20+
abbreviation: string;
21+
};
22+
subject: {
23+
name: string;
24+
abbreviation: string;
25+
};
26+
}
27+
28+
export const getAbsencesFromDatabase = async (): Promise<
29+
AbsenceWithRelations[]
30+
> => {
31+
try {
32+
const absences: AbsenceWithRelations[] = await prisma.absence.findMany({
33+
select: {
34+
lessonDate: true,
35+
subject: {
36+
select: {
37+
name: true,
38+
abbreviation: true,
39+
},
40+
},
41+
lessonPlan: true,
42+
reasonOfAbsence: true,
43+
notes: true,
44+
absentTeacher: {
45+
select: {
46+
firstName: true,
47+
lastName: true,
48+
email: true,
49+
},
50+
},
51+
substituteTeacher: {
52+
select: {
53+
firstName: true,
54+
lastName: true,
55+
email: true,
56+
},
57+
},
58+
location: {
59+
select: {
60+
name: true,
61+
abbreviation: true,
62+
},
63+
},
64+
},
65+
});
66+
67+
return absences;
68+
} catch (err) {
69+
console.error('Error fetching absences:', err);
70+
throw err;
71+
}
72+
};

app/api/getAbsences/route.ts

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,9 @@
1-
import { prisma } from '@utils/prisma';
21
import { NextResponse } from 'next/server';
3-
4-
export interface AbsenceWithRelations {
5-
lessonDate: Date;
6-
lessonPlan: string | null;
7-
reasonOfAbsence: string;
8-
notes: string | null;
9-
absentTeacher: {
10-
firstName: string;
11-
lastName: string;
12-
email: string;
13-
};
14-
substituteTeacher: {
15-
firstName: string;
16-
lastName: string;
17-
email: string;
18-
} | null;
19-
location: {
20-
name: string;
21-
abbreviation: string;
22-
};
23-
subject: {
24-
name: string;
25-
abbreviation: string;
26-
};
27-
}
2+
import { AbsenceWithRelations, getAbsencesFromDatabase } from './absences';
283

294
export async function GET() {
305
try {
31-
const absences: AbsenceWithRelations[] = await prisma.absence.findMany({
32-
select: {
33-
lessonDate: true,
34-
subject: {
35-
select: {
36-
name: true,
37-
abbreviation: true,
38-
},
39-
},
40-
lessonPlan: true,
41-
reasonOfAbsence: true,
42-
notes: true,
43-
absentTeacher: {
44-
select: {
45-
firstName: true,
46-
lastName: true,
47-
email: true,
48-
},
49-
},
50-
substituteTeacher: {
51-
select: {
52-
firstName: true,
53-
lastName: true,
54-
email: true,
55-
},
56-
},
57-
location: {
58-
select: {
59-
name: true,
60-
abbreviation: true,
61-
},
62-
},
63-
},
64-
});
6+
const absences: AbsenceWithRelations[] = await getAbsencesFromDatabase();
657

668
if (!absences.length) {
679
return NextResponse.json({ events: [] }, { status: 200 });

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

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

src/pages/calendar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import dayGridPlugin from '@fullcalendar/daygrid';
44
import interactionPlugin from '@fullcalendar/interaction';
55
import { Box, Flex, useToast, useTheme } from '@chakra-ui/react';
66
import { EventInput, EventContentArg } from '@fullcalendar/core';
7-
import { AbsenceWithRelations } from '../../app/api/getAbsences/route';
7+
import { AbsenceWithRelations } from '../../app/api/getAbsences/absences';
88
import Sidebar from '../components/CalendarSidebar';
99
import CalendarHeader from '../components/CalendarHeader';
1010
import { Global } from '@emotion/react';

src/pages/ics.tsx

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

56
export default function CalendarDownload() {
67
const [error, setError] = useState<string | null>(null);
78

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-
};
9+
const CALENDAR_NAME: string = 'Sistema Absences';
6310

6411
const downloadFile = (file: File) => {
6512
const url = URL.createObjectURL(file);
@@ -77,8 +24,21 @@ export default function CalendarDownload() {
7724
setError(null);
7825

7926
try {
80-
const events = await searchAbsences();
81-
const file = await createCalendarFile(events);
27+
const res = await fetch('/api/getAbsences/');
28+
29+
if (!res.ok) {
30+
throw new Error(`Failed to fetch: ${res.statusText}`);
31+
}
32+
const data = await res.json();
33+
if (!data.events || !Array.isArray(data.events)) {
34+
throw new Error('Invalid data format.');
35+
}
36+
37+
const icsEvents = data.events.map((eventData: AbsenceWithRelations) =>
38+
convertAbsenceToICSEvent(eventData, CALENDAR_NAME)
39+
);
40+
41+
const file = await createCalendarFile(icsEvents);
8242
downloadFile(file);
8343
} catch (error) {
8444
console.error('Error during download process:', error);

0 commit comments

Comments
 (0)