Skip to content

Commit 032b9bf

Browse files
committed
Add .ics file
1 parent 9ad4f5a commit 032b9bf

4 files changed

Lines changed: 168 additions & 0 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
},
1212
"dependencies": {
1313
"@bprogress/next": "^3.2.12",
14+
"dayjs": "^1.11.18",
15+
"ical-generator": "^9.0.0",
1416
"lucide-react": "^0.541.0",
1517
"motion": "^12.23.12",
1618
"next": "15.5.0",

pnpm-lock.yaml

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import dayjs, { type Dayjs } from "dayjs";
2+
import timezone from "dayjs/plugin/timezone";
3+
import utc from "dayjs/plugin/utc";
4+
import ical, {
5+
ICalCalendarMethod,
6+
ICalEventRepeatingFreq,
7+
} from "ical-generator";
8+
import { STATIC_CONFIG } from "@/config";
9+
import { listSchedules } from "@/lib/collection";
10+
11+
dayjs.extend(utc);
12+
dayjs.extend(timezone);
13+
14+
export const dynamic = "force-static";
15+
export async function GET() {
16+
const schedules = listSchedules();
17+
18+
const calendar = ical({
19+
name: "Terpal B24 Schedule",
20+
timezone: "Asia/Jakarta",
21+
method: ICalCalendarMethod.REQUEST,
22+
});
23+
24+
schedules.forEach((day) => {
25+
const startDay = dayjs
26+
.tz(STATIC_CONFIG.START_SEMESTER, "Asia/Jakarta")
27+
.set("day", day.parsedDay);
28+
29+
day.items.forEach((course) => {
30+
const [startHour, startMinute] = course.startAt.split(":").map(Number);
31+
const [endHour, endMinute] = course.endAt.split(":").map(Number);
32+
33+
const currentStart = startDay
34+
.set("hour", startHour)
35+
.set("minute", startMinute);
36+
37+
const currentEnd = startDay.set("hour", endHour).set("minute", endMinute);
38+
39+
const event = calendar.createEvent({
40+
start: currentStart.utc(),
41+
end: currentEnd.utc(),
42+
summary: `${course.subject.code} - ${course.subject.title} (${course.type === "practice" ? "Praktikum" : "Teori"})`,
43+
description: `Dosen: ${course.lecturer.name}`,
44+
location: course.room,
45+
});
46+
47+
const excludeDates: Dayjs[] = [];
48+
STATIC_CONFIG.BLOCKING_TIME.forEach((block) => {
49+
const blockStart = dayjs.tz(block.start, "Asia/Jakarta");
50+
const blockEnd = dayjs.tz(block.end, "Asia/Jakarta");
51+
let date = blockStart;
52+
while (date <= blockEnd) {
53+
if (date.day() === currentStart.day()) {
54+
excludeDates.push(
55+
date.set("hour", startHour).set("minute", startMinute).utc(),
56+
);
57+
}
58+
date = date.add(1, "day");
59+
}
60+
});
61+
62+
const repeatEnd = dayjs
63+
.tz(STATIC_CONFIG.END_SEMESTER, "Asia/Jakarta")
64+
.subtract(6, "day")
65+
.set("day", day.parsedDay)
66+
.set("hour", endHour)
67+
.set("minute", endMinute);
68+
69+
event.repeating({
70+
freq: ICalEventRepeatingFreq.WEEKLY,
71+
until: repeatEnd.utc(),
72+
interval: 1,
73+
exclude: excludeDates,
74+
});
75+
});
76+
});
77+
78+
return new Response(calendar.toString(), {
79+
headers: {
80+
"Content-Type": "text/calendar",
81+
},
82+
});
83+
}

src/config.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export const STATIC_CONFIG = {
2+
START_SEMESTER: "2025-09-08T00:00:00",
3+
END_SEMESTER: "2026-01-18T23:59:59",
4+
BLOCKING_TIME: [
5+
{
6+
title: "Minggu Pengganti ATS",
7+
start: "2025-10-20T00:00:00",
8+
end: "2025-10-26T23:59:59",
9+
},
10+
{
11+
title: "ATS",
12+
start: "2025-10-27T00:00:00",
13+
end: "2025-11-09T23:59:59",
14+
},
15+
{
16+
title: "Minggu Pengganti AAS",
17+
start: "2025-12-29T00:00:00",
18+
end: "2026-01-04T23:59:59",
19+
},
20+
{
21+
title: "AAS",
22+
start: "2026-01-05T00:00:00",
23+
end: "2026-01-18T23:59:59",
24+
},
25+
],
26+
};

0 commit comments

Comments
 (0)