diff --git a/components/EventsCalendar.tsx b/components/EventsCalendar.tsx index 9ae8ae3cb..a6ca89f51 100644 --- a/components/EventsCalendar.tsx +++ b/components/EventsCalendar.tsx @@ -8,7 +8,10 @@ import Modal from '@mui/material/Modal' import Box from '@mui/material/Box' import { prefix } from '@/utils/prefix' import Image from 'next/image' -import { MapPin } from 'iconoir-react' +import { CalendarPlus, MapPin } from 'iconoir-react' +import { IconButton } from '@mui/material' +import ical from 'ical-generator' +import slugify from '@/utils/slugify' const EventsCalendar: React.FC = () => { const { events, loading, error } = useCalendarEvents() @@ -28,6 +31,29 @@ const EventsCalendar: React.FC = () => { setOpen(false) } + const handleDownloadIcsFile = () => { + const calendar = ical({ + prodId: '//comp-soc.com//2024//EN', + events: [ + { + start: event.extendedProps.start_, + end: event.extendedProps.end_, + summary: event.title, + description: event.extendedProps.description, + location: event.extendedProps.location, + }, + ], + }) + const icsData = calendar.toString() + const blob = new Blob([icsData], { type: 'text/calendar' }) + const url = URL.createObjectURL(blob) + const link = document.createElement('a') + link.download = + slugify(`${event.title}-${event.extendedProps.formattedDate}`) + '.ics' + link.href = url + link.click() + } + const style = { position: 'absolute', top: '50%', @@ -160,19 +186,30 @@ const EventsCalendar: React.FC = () => {
{event && ( <> -
-
- {event.extendedProps.sig.icon.alt} -
{event.title}
-
+
+ +
+ {event.extendedProps.sig.icon.alt} +
{event.title}
+
+ + + +
{' '} {event.extendedProps.formattedDate} diff --git a/constants/calendarevents.ts b/constants/calendarevents.ts index 765c7aca9..dff8eed4b 100644 --- a/constants/calendarevents.ts +++ b/constants/calendarevents.ts @@ -139,6 +139,8 @@ function transformEvents( title: event.summary, start: event.start.dateTime || event.start.date, end: event.end.dateTime || event.end.date, + start_: event.start.dateTime || event.start.date, + end_: event.end.dateTime || event.end.date, color: sig.backgroundColor, textColor: sig.textColor, sig: sig, diff --git a/package-lock.json b/package-lock.json index c28f12319..8278b29e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "date-fns": "^3.6.0", "framer-motion": "^11.3.24", "gray-matter": "^4.0.3", + "ical-generator": "^8.0.0", "iconoir-react": "^7.7.0", "matter-js": "^0.19.0", "mui": "^0.0.1", @@ -3895,6 +3896,56 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/ical-generator": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ical-generator/-/ical-generator-8.0.0.tgz", + "integrity": "sha512-CvVKK3JJrKop6z7i7/NS69FjYdR6ux1LswIeiZ3yaicX7ocMFLQI475JhQabCT7koUkaCVFNVxLaYaxtdPgwww==", + "dependencies": { + "uuid-random": "^1.3.2" + }, + "engines": { + "node": "18 || 20 || >=22.0.0" + }, + "peerDependencies": { + "@touch4it/ical-timezones": ">=1.6.0", + "@types/luxon": ">= 1.26.0", + "@types/mocha": ">= 8.2.1", + "dayjs": ">= 1.10.0", + "luxon": ">= 1.26.0", + "moment": ">= 2.29.0", + "moment-timezone": ">= 0.5.33", + "rrule": ">= 2.6.8" + }, + "peerDependenciesMeta": { + "@touch4it/ical-timezones": { + "optional": true + }, + "@types/luxon": { + "optional": true + }, + "@types/mocha": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-timezone": { + "optional": true + }, + "rrule": { + "optional": true + } + } + }, "node_modules/iconoir-react": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/iconoir-react/-/iconoir-react-7.7.0.tgz", @@ -7658,6 +7709,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid-random": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/uuid-random/-/uuid-random-1.3.2.tgz", + "integrity": "sha512-UOzej0Le/UgkbWEO8flm+0y+G+ljUon1QWTEZOq1rnMAsxo2+SckbiZdKzAHHlVh6gJqI1TjC/xwgR50MuCrBQ==" + }, "node_modules/vfile": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", diff --git a/package.json b/package.json index 41dc12cda..ec7e8a5dd 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "date-fns": "^3.6.0", "framer-motion": "^11.3.24", "gray-matter": "^4.0.3", + "ical-generator": "^8.0.0", "iconoir-react": "^7.7.0", "matter-js": "^0.19.0", "mui": "^0.0.1", diff --git a/utils/slugify.ts b/utils/slugify.ts new file mode 100644 index 000000000..c1f6edd98 --- /dev/null +++ b/utils/slugify.ts @@ -0,0 +1,11 @@ +function slugify(s: string) { + s = s + .toLowerCase() + .trim() + .replace(/[^a-z0-9 -]/g, '') + .replace(/\s+/g, '-') + .replace(/-+/g, '-') + return s +} + +export default slugify