create Events Calendar View

- install full-calendar npm packages
- create FullCalendar component
- create Events Calendar route
- Fix: remove unused imports in NavBar.vue
This commit is contained in:
summersamara 2023-12-10 22:56:37 +01:00
parent 863a1dbe3f
commit 5095749157
6 changed files with 167 additions and 8 deletions

62
package-lock.json generated
View file

@ -11,6 +11,11 @@
"@apollo/client": "^3.3.16", "@apollo/client": "^3.3.16",
"@framasoft/socket": "^1.0.0", "@framasoft/socket": "^1.0.0",
"@framasoft/socket-apollo-link": "^1.0.0", "@framasoft/socket-apollo-link": "^1.0.0",
"@fullcalendar/core": "^6.1.10",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/icalendar": "^6.1.10",
"@fullcalendar/interaction": "^6.1.10",
"@fullcalendar/vue3": "^6.1.10",
"@oruga-ui/oruga-next": "^0.7.0", "@oruga-ui/oruga-next": "^0.7.0",
"@sentry/tracing": "^7.1", "@sentry/tracing": "^7.1",
"@sentry/vue": "^7.1", "@sentry/vue": "^7.1",
@ -55,6 +60,7 @@
"graphql": "^16.8.1", "graphql": "^16.8.1",
"graphql-tag": "^2.10.3", "graphql-tag": "^2.10.3",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"ical.js": "^1.5.0",
"intersection-observer": "^0.12.0", "intersection-observer": "^0.12.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"leaflet": "^1.4.0", "leaflet": "^1.4.0",
@ -2626,6 +2632,48 @@
"zen-observable": "^0.10.0" "zen-observable": "^0.10.0"
} }
}, },
"node_modules/@fullcalendar/core": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.10.tgz",
"integrity": "sha512-oTXGJSAGpCf1oY+CKp5qYjMHkJCPBkJ3SHitl63n8Q6xKeiwQ4EF6Au451euUovREwJpLmD1AyZrCnWmtB9AVg==",
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.10.tgz",
"integrity": "sha512-Z4GRm1IyHKgxXFTWGcEI0nTsvYOIkpE0aMt3/o3ER2SZkF+hfwcDFhtj0c9+WhMjXFIWYeoTnA9rUOY7Zl/nxA==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10"
}
},
"node_modules/@fullcalendar/icalendar": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/icalendar/-/icalendar-6.1.10.tgz",
"integrity": "sha512-TXjtZhjYIQZjeqULRjwDd2VWlymdhJmltaN26YS0dcGuCrQhJJ3x/sODVbVaW1mvbMjnjXYUE8AhdpxvhYGIJg==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10",
"ical.js": "^1.4.0"
}
},
"node_modules/@fullcalendar/interaction": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.10.tgz",
"integrity": "sha512-aZRlwCpmDasq2RNeWV0ub20Uevare9Cb6iMlxCacx0fhOC14H28G9d1FsduJIecInL84SPGwt5ItqAYMsWv7zw==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10"
}
},
"node_modules/@fullcalendar/vue3": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@fullcalendar/vue3/-/vue3-6.1.10.tgz",
"integrity": "sha512-YMYBQx0TlWNuN4G6ra2dkf5cCF5aVi/2zDLGLvLqe2Nk2o7uNbTkrCSG40061OepWQlJv+hYqm1JukLRmyqi4Q==",
"peerDependencies": {
"@fullcalendar/core": "~6.1.10",
"vue": "^3.0.11"
}
},
"node_modules/@graphql-typed-document-node/core": { "node_modules/@graphql-typed-document-node/core": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz",
@ -8079,6 +8127,11 @@
"url": "https://github.com/sponsors/typicode" "url": "https://github.com/sponsors/typicode"
} }
}, },
"node_modules/ical.js": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/ical.js/-/ical.js-1.5.0.tgz",
"integrity": "sha512-7ZxMkogUkkaCx810yp0ZGKvq1ZpRgJeornPttpoxe6nYZ3NLesZe1wWMXDdwTkj/b5NtXT+Y16Aakph/ao98ZQ=="
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@ -10437,6 +10490,15 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
}, },
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",

View file

@ -27,6 +27,11 @@
"@apollo/client": "^3.3.16", "@apollo/client": "^3.3.16",
"@framasoft/socket": "^1.0.0", "@framasoft/socket": "^1.0.0",
"@framasoft/socket-apollo-link": "^1.0.0", "@framasoft/socket-apollo-link": "^1.0.0",
"@fullcalendar/core": "^6.1.10",
"@fullcalendar/daygrid": "^6.1.10",
"@fullcalendar/icalendar": "^6.1.10",
"@fullcalendar/interaction": "^6.1.10",
"@fullcalendar/vue3": "^6.1.10",
"@oruga-ui/oruga-next": "^0.7.0", "@oruga-ui/oruga-next": "^0.7.0",
"@sentry/tracing": "^7.1", "@sentry/tracing": "^7.1",
"@sentry/vue": "^7.1", "@sentry/vue": "^7.1",
@ -71,6 +76,7 @@
"graphql": "^16.8.1", "graphql": "^16.8.1",
"graphql-tag": "^2.10.3", "graphql-tag": "^2.10.3",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
"ical.js": "^1.5.0",
"intersection-observer": "^0.12.0", "intersection-observer": "^0.12.0",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"leaflet": "^1.4.0", "leaflet": "^1.4.0",

View file

@ -0,0 +1,51 @@
<template>
<FullCalendar :options="calendarOptions">
<template v-slot:eventContent="arg">
<span class="text-violet-3 dark:text-white font-bold">
{{ arg.event.title }}
</span>
</template>
</FullCalendar>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { locale } from "@/utils/i18n";
import { computed } from "vue";
import FullCalendar from "@fullcalendar/vue3";
import dayGridPlugin from "@fullcalendar/daygrid";
import iCalendarPlugin from "@fullcalendar/icalendar";
import interactionPlugin from "@fullcalendar/interaction";
const props = defineProps<{
icsFeedUrl: string;
}>();
const { t } = useI18n({ useScope: "global" });
const calendarOptions = computed((): object => {
return {
plugins: [dayGridPlugin, iCalendarPlugin, interactionPlugin],
initialView: "dayGridMonth",
events: {
url: props.icsFeedUrl,
format: "ics",
},
eventClassNames: "line-clamp-3 bg-mbz-yellow dark:bg-mbz-purple",
headerToolbar: {
left: "prev,next,today",
center: "title",
right: "dayGridWeek,dayGridMonth", // user can switch between the two
},
locale: locale,
firstDay: 1,
buttonText: {
today: t("Today"),
month: t("Month"),
week: t("Week"),
day: t("Day"),
list: t("List"),
},
};
});
</script>

View file

@ -165,9 +165,20 @@
<ul <ul
class="flex flex-col md:flex-row md:space-x-8 mt-2 md:mt-0 md:font-lightbold" class="flex flex-col md:flex-row md:space-x-8 mt-2 md:mt-0 md:font-lightbold"
> >
<search-fields
v-if="showMobileMenu"
class="m-auto w-auto"
v-model:search="search"
v-model:location="location"
/>
<search-fields v-if="showMobileMenu" class="m-auto w-auto" v-model:search="search" v-model:location="location"/> <li class="m-auto">
<router-link
:to="{ name: RouteName.EVENT_CALENDAR }"
class="block py-2 pr-4 pl-3 text-zinc-700 border-b border-gray-100 hover:bg-zinc-50 md:hover:bg-transparent md:border-0 md:hover:text-mbz-purple-700 md:p-0 dark:text-zinc-400 md:dark:hover:text-white dark:hover:bg-zinc-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700"
>{{ t("Calendar") }}</router-link
>
</li>
<li class="m-auto" v-if="currentActor?.id"> <li class="m-auto" v-if="currentActor?.id">
<router-link <router-link
:to="{ name: RouteName.MY_EVENTS }" :to="{ name: RouteName.MY_EVENTS }"
@ -197,8 +208,12 @@
> >
</li> </li>
<search-fields v-if="!showMobileMenu" class="m-auto w-auto" v-model:search="search" v-model:location="location"/> <search-fields
v-if="!showMobileMenu"
class="m-auto w-auto"
v-model:search="search"
v-model:location="location"
/>
</ul> </ul>
</div> </div>
</div> </div>
@ -209,19 +224,18 @@
import MobilizonLogo from "@/components/MobilizonLogo.vue"; import MobilizonLogo from "@/components/MobilizonLogo.vue";
import { ICurrentUserRole } from "@/types/enums"; import { ICurrentUserRole } from "@/types/enums";
import { logout } from "../utils/auth"; import { logout } from "../utils/auth";
import { IPerson, displayName } from "../types/actor"; import { displayName } from "../types/actor";
import RouteName from "../router/name"; import RouteName from "../router/name";
import { computed, onMounted, ref, watch } from "vue"; import { computed, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import AccountCircle from "vue-material-design-icons/AccountCircle.vue"; import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
import Inbox from "vue-material-design-icons/Inbox.vue";
import { useCurrentUserClient } from "@/composition/apollo/user"; import { useCurrentUserClient } from "@/composition/apollo/user";
import { import {
useCurrentActorClient, useCurrentActorClient,
useCurrentUserIdentities, useCurrentUserIdentities,
} from "@/composition/apollo/actor"; } from "@/composition/apollo/actor";
import { useLazyQuery, useMutation } from "@vue/apollo-composable"; import { useMutation } from "@vue/apollo-composable";
import { UPDATE_DEFAULT_ACTOR } from "@/graphql/actor"; import { UPDATE_DEFAULT_ACTOR } from "@/graphql/actor";
import { changeIdentity } from "@/utils/identity"; import { changeIdentity } from "@/utils/identity";
import { useRegistrationConfig } from "@/composition/apollo/config"; import { useRegistrationConfig } from "@/composition/apollo/config";

View file

@ -10,6 +10,7 @@ const myEvents = () => import("@/views/Event/MyEventsView.vue");
export enum EventRouteName { export enum EventRouteName {
EVENT_LIST = "EventList", EVENT_LIST = "EventList",
EVENT_CALENDAR = "EventCalendar",
CREATE_EVENT = "CreateEvent", CREATE_EVENT = "CreateEvent",
MY_EVENTS = "MyEvents", MY_EVENTS = "MyEvents",
EDIT_EVENT = "EditEvent", EDIT_EVENT = "EditEvent",
@ -26,6 +27,14 @@ export enum EventRouteName {
} }
export const eventRoutes: RouteRecordRaw[] = [ export const eventRoutes: RouteRecordRaw[] = [
{
path: "/events/calendar",
name: EventRouteName.EVENT_CALENDAR,
component: import("../views/Event/CalendarView.vue"),
meta: {
requiredAuth: false,
},
},
{ {
path: "/events/create", path: "/events/create",
name: EventRouteName.CREATE_EVENT, name: EventRouteName.CREATE_EVENT,

View file

@ -0,0 +1,17 @@
<template>
<div class="container mx-auto px-1 mb-6">
<h1>
{{ t("Calendar") }}
</h1>
<div class="p-2">
<FullCalendar ics-feed-url="/feed/instance/ics" />
</div>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import FullCalendar from "@/components/FullCalendar.vue";
const { t } = useI18n({ useScope: "global" });
</script>