b53867181f
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
354 lines
9.4 KiB
Vue
354 lines
9.4 KiB
Vue
<template>
|
|
<div class="section container">
|
|
<h1 class="title">
|
|
{{ $t("My events") }}
|
|
</h1>
|
|
<p>
|
|
{{
|
|
$t(
|
|
"You will find here all the events you have created or of which you are a participant."
|
|
)
|
|
}}
|
|
</p>
|
|
<div class="buttons">
|
|
<router-link
|
|
class="button is-primary"
|
|
:to="{ name: RouteName.CREATE_EVENT }"
|
|
>{{ $t("Create event") }}</router-link
|
|
>
|
|
</div>
|
|
<b-loading :active.sync="$apollo.loading"></b-loading>
|
|
<section v-if="futureParticipations.length > 0">
|
|
<subtitle>
|
|
{{ $t("Upcoming") }}
|
|
</subtitle>
|
|
<transition-group name="list" tag="p">
|
|
<div v-for="month in monthlyFutureParticipations" :key="month[0]">
|
|
<span class="upcoming-month">{{ month[0] }}</span>
|
|
<EventListCard
|
|
v-for="participation in month[1]"
|
|
:key="participation.id"
|
|
:participation="participation"
|
|
:options="{ hideDate: false }"
|
|
@event-deleted="eventDeleted"
|
|
class="participation"
|
|
/>
|
|
</div>
|
|
</transition-group>
|
|
<div class="columns is-centered">
|
|
<b-button
|
|
class="column is-narrow"
|
|
v-if="
|
|
hasMoreFutureParticipations && futureParticipations.length === limit
|
|
"
|
|
@click="loadMoreFutureParticipations"
|
|
size="is-large"
|
|
type="is-primary"
|
|
>{{ $t("Load more") }}</b-button
|
|
>
|
|
</div>
|
|
</section>
|
|
<section v-if="drafts.length > 0">
|
|
<subtitle>
|
|
{{ $t("Drafts") }}
|
|
</subtitle>
|
|
<div class="columns is-multiline">
|
|
<EventCard
|
|
v-for="draft in drafts"
|
|
:key="draft.uuid"
|
|
:event="draft"
|
|
class="is-one-quarter-desktop column"
|
|
/>
|
|
</div>
|
|
</section>
|
|
<section v-if="pastParticipations.length > 0">
|
|
<subtitle>
|
|
{{ $t("Past events") }}
|
|
</subtitle>
|
|
<transition-group name="list" tag="p">
|
|
<div v-for="month in monthlyPastParticipations" :key="month[0]">
|
|
<span class="past-month">{{ month[0] }}</span>
|
|
<EventListCard
|
|
v-for="participation in month[1]"
|
|
:key="participation.id"
|
|
:participation="participation"
|
|
:options="{ hideDate: false }"
|
|
@event-deleted="eventDeleted"
|
|
class="participation"
|
|
/>
|
|
</div>
|
|
</transition-group>
|
|
<div class="columns is-centered">
|
|
<b-button
|
|
class="column is-narrow"
|
|
v-if="
|
|
hasMorePastParticipations && pastParticipations.length === limit
|
|
"
|
|
@click="loadMorePastParticipations"
|
|
size="is-large"
|
|
type="is-primary"
|
|
>{{ $t("Load more") }}</b-button
|
|
>
|
|
</div>
|
|
</section>
|
|
<section
|
|
class="has-text-centered not-found"
|
|
v-if="
|
|
futureParticipations.length === 0 &&
|
|
pastParticipations.length === 0 &&
|
|
!$apollo.loading
|
|
"
|
|
>
|
|
<div class="columns is-vertical is-centered">
|
|
<div class="column is-three-quarters">
|
|
<div class="img-container" :class="{ webp: supportsWebPFormat }" />
|
|
<div class="content has-text-centered">
|
|
<p>
|
|
{{ $t("You didn't create or join any event yet.") }}
|
|
<i18n path="Do you wish to {create_event} or {explore_events}?">
|
|
<router-link
|
|
:to="{ name: RouteName.CREATE_EVENT }"
|
|
slot="create_event"
|
|
>{{ $t("create an event") }}</router-link
|
|
>
|
|
<router-link
|
|
:to="{ name: RouteName.SEARCH }"
|
|
slot="explore_events"
|
|
>{{ $t("explore the events") }}</router-link
|
|
>
|
|
</i18n>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-property-decorator";
|
|
import { ParticipantRole } from "@/types/enums";
|
|
import RouteName from "@/router/name";
|
|
import { supportsWebPFormat } from "@/utils/support";
|
|
import { IParticipant, Participant } from "../../types/participant.model";
|
|
import {
|
|
LOGGED_USER_PARTICIPATIONS,
|
|
LOGGED_USER_DRAFTS,
|
|
} from "../../graphql/actor";
|
|
import { EventModel, IEvent } from "../../types/event.model";
|
|
import EventListCard from "../../components/Event/EventListCard.vue";
|
|
import EventCard from "../../components/Event/EventCard.vue";
|
|
import Subtitle from "../../components/Utils/Subtitle.vue";
|
|
|
|
@Component({
|
|
components: {
|
|
Subtitle,
|
|
EventCard,
|
|
EventListCard,
|
|
},
|
|
apollo: {
|
|
futureParticipations: {
|
|
query: LOGGED_USER_PARTICIPATIONS,
|
|
fetchPolicy: "cache-and-network",
|
|
variables: {
|
|
page: 1,
|
|
limit: 10,
|
|
afterDateTime: new Date().toISOString(),
|
|
},
|
|
update: (data) =>
|
|
data.loggedUser.participations.elements.map(
|
|
(participation: IParticipant) => new Participant(participation)
|
|
),
|
|
},
|
|
drafts: {
|
|
query: LOGGED_USER_DRAFTS,
|
|
fetchPolicy: "cache-and-network",
|
|
variables: {
|
|
page: 1,
|
|
limit: 10,
|
|
},
|
|
update: (data) =>
|
|
data.loggedUser.drafts.map((event: IEvent) => new EventModel(event)),
|
|
},
|
|
pastParticipations: {
|
|
query: LOGGED_USER_PARTICIPATIONS,
|
|
fetchPolicy: "cache-and-network",
|
|
variables: {
|
|
page: 1,
|
|
limit: 10,
|
|
beforeDateTime: new Date().toISOString(),
|
|
},
|
|
update: (data) =>
|
|
data.loggedUser.participations.elements.map(
|
|
(participation: IParticipant) => new Participant(participation)
|
|
),
|
|
},
|
|
},
|
|
metaInfo() {
|
|
return {
|
|
title: this.$t("My events") as string,
|
|
};
|
|
},
|
|
})
|
|
export default class MyEvents extends Vue {
|
|
futurePage = 1;
|
|
|
|
pastPage = 1;
|
|
|
|
limit = 10;
|
|
|
|
futureParticipations: IParticipant[] = [];
|
|
|
|
hasMoreFutureParticipations = true;
|
|
|
|
pastParticipations: IParticipant[] = [];
|
|
|
|
hasMorePastParticipations = true;
|
|
|
|
drafts: IEvent[] = [];
|
|
|
|
RouteName = RouteName;
|
|
|
|
supportsWebPFormat = supportsWebPFormat;
|
|
|
|
static monthlyParticipations(
|
|
participations: IParticipant[],
|
|
revertSort = false
|
|
): Map<string, Participant[]> {
|
|
const res = participations.filter(
|
|
({ event, role }) =>
|
|
event.beginsOn != null && role !== ParticipantRole.REJECTED
|
|
);
|
|
if (revertSort) {
|
|
res.sort(
|
|
(a: IParticipant, b: IParticipant) =>
|
|
b.event.beginsOn.getTime() - a.event.beginsOn.getTime()
|
|
);
|
|
} else {
|
|
res.sort(
|
|
(a: IParticipant, b: IParticipant) =>
|
|
a.event.beginsOn.getTime() - b.event.beginsOn.getTime()
|
|
);
|
|
}
|
|
return res.reduce(
|
|
(acc: Map<string, IParticipant[]>, participation: IParticipant) => {
|
|
const month = new Date(participation.event.beginsOn).toLocaleDateString(
|
|
undefined,
|
|
{
|
|
year: "numeric",
|
|
month: "long",
|
|
}
|
|
);
|
|
const filteredParticipations: IParticipant[] = acc.get(month) || [];
|
|
filteredParticipations.push(participation);
|
|
acc.set(month, filteredParticipations);
|
|
return acc;
|
|
},
|
|
new Map()
|
|
);
|
|
}
|
|
|
|
get monthlyFutureParticipations(): Map<string, Participant[]> {
|
|
return MyEvents.monthlyParticipations(this.futureParticipations);
|
|
}
|
|
|
|
get monthlyPastParticipations(): Map<string, Participant[]> {
|
|
return MyEvents.monthlyParticipations(this.pastParticipations, true);
|
|
}
|
|
|
|
loadMoreFutureParticipations(): void {
|
|
this.futurePage += 1;
|
|
this.$apollo.queries.futureParticipations.fetchMore({
|
|
// New variables
|
|
variables: {
|
|
page: this.futurePage,
|
|
limit: this.limit,
|
|
},
|
|
});
|
|
}
|
|
|
|
loadMorePastParticipations(): void {
|
|
this.pastPage += 1;
|
|
this.$apollo.queries.pastParticipations.fetchMore({
|
|
// New variables
|
|
variables: {
|
|
page: this.pastPage,
|
|
limit: this.limit,
|
|
},
|
|
});
|
|
}
|
|
|
|
eventDeleted(eventid: string): void {
|
|
this.futureParticipations = this.futureParticipations.filter(
|
|
(participation) => participation.event.id !== eventid
|
|
);
|
|
this.pastParticipations = this.pastParticipations.filter(
|
|
(participation) => participation.event.id !== eventid
|
|
);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
<style lang="scss" scoped>
|
|
main > .container {
|
|
background: $white;
|
|
|
|
& > h1 {
|
|
margin: 10px auto 5px;
|
|
}
|
|
}
|
|
|
|
.participation {
|
|
margin: 1rem auto;
|
|
}
|
|
|
|
section {
|
|
.upcoming-month,
|
|
.past-month {
|
|
text-transform: capitalize;
|
|
display: inline-block;
|
|
position: relative;
|
|
font-size: 1.3rem;
|
|
|
|
&::after {
|
|
background: $orange-3;
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 100%;
|
|
content: "";
|
|
width: calc(100% + 30px);
|
|
height: 3px;
|
|
max-width: 150px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.not-found {
|
|
.img-container {
|
|
background-image: url("../../../public/img/pics/event_creation-480w.jpg");
|
|
@media (min-resolution: 2dppx) {
|
|
& {
|
|
background-image: url("../../../public/img/pics/event_creation-1024w.jpg");
|
|
}
|
|
}
|
|
|
|
&.webp {
|
|
background-image: url("../../../public/img/pics/event_creation-480w.webp");
|
|
@media (min-resolution: 2dppx) {
|
|
& {
|
|
background-image: url("../../../public/img/pics/event_creation-1024w.webp");
|
|
}
|
|
}
|
|
}
|
|
max-width: 450px;
|
|
height: 300px;
|
|
box-shadow: 0 0 8px 8px white inset;
|
|
background-size: cover;
|
|
border-radius: 10px;
|
|
margin: auto auto 1rem;
|
|
}
|
|
}
|
|
</style>
|