Add admin interface to manage instances subscriptions

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2019-12-03 11:29:51 +01:00
parent 0a96d70348
commit 334d66bf5d
141 changed files with 4198 additions and 1923 deletions

View File

@@ -29,7 +29,7 @@
<address-auto-complete v-model="event.physicalAddress" />
<b-field :label="$t('Organizer')">
<identity-picker-wrapper v-model="event.organizerActor"></identity-picker-wrapper>
<identity-picker-wrapper v-model="event.organizerActor" />
</b-field>
<div class="field">
@@ -92,7 +92,7 @@
<div class="box" v-if="limitedPlaces">
<b-field :label="$t('Number of places')">
<b-numberinput controls-position="compact" min="0" v-model="event.options.maximumAttendeeCapacity"></b-numberinput>
<b-numberinput controls-position="compact" min="0" v-model="event.options.maximumAttendeeCapacity" />
</b-field>
<!--
<b-field>
@@ -145,21 +145,21 @@
name="status"
type="is-warning"
:native-value="EventStatus.TENTATIVE">
<b-icon icon="calendar-question"></b-icon>
<b-icon icon="calendar-question" />
{{ $t('Tentative: Will be confirmed later') }}
</b-radio-button>
<b-radio-button v-model="event.status"
name="status"
type="is-success"
:native-value="EventStatus.CONFIRMED">
<b-icon icon="calendar-check"></b-icon>
<b-icon icon="calendar-check" />
{{ $t('Confirmed: Will happen') }}
</b-radio-button>
<b-radio-button v-model="event.status"
name="status"
type="is-danger"
:native-value="EventStatus.CANCELLED">
<b-icon icon="calendar-remove"></b-icon>
<b-icon icon="calendar-remove" />
{{ $t("Cancelled: Won't happen") }}
</b-radio-button>
</b-field>
@@ -191,7 +191,7 @@
</div>
</form>
</b-modal>
<span ref="bottomObserver"></span>
<span ref="bottomObserver" />
<nav role="navigation" aria-label="main navigation" class="navbar" :class="{'is-fixed-bottom': showFixedNavbar }">
<div class="container">
<div class="navbar-menu">
@@ -395,6 +395,11 @@ export default class EditEvent extends Vue {
}
}
@Watch('currentActor')
setCurrentActor() {
this.event.organizerActor = this.currentActor;
}
private validateForm() {
const form = this.$refs.form as HTMLFormElement;
if (form.checkValidity()) {

View File

@@ -1,6 +1,8 @@
import {ParticipantRole} from "@/types/event.model";
import {ParticipantRole} from "@/types/event.model";
<template>
<div class="container">
<b-loading :active.sync="$apollo.loading"></b-loading>
<b-loading :active.sync="$apollo.loading" />
<transition appear name="fade" mode="out-in">
<div>
<div class="header-picture" v-if="event.picture" :style="`background-image: url('${event.picture.url}')`" />
@@ -9,7 +11,7 @@
<div class="title-and-participate-button">
<div class="title-wrapper">
<div class="date-component">
<date-calendar-icon :date="event.beginsOn"></date-calendar-icon>
<date-calendar-icon :date="event.beginsOn" />
</div>
<div class="title-and-informations">
<h1 class="title">{{ event.title }}</h1>
@@ -49,7 +51,7 @@
<template>
<span>{{ $t('Event already passed')}}</span>
</template>
<b-icon icon="menu-down"></b-icon>
<b-icon icon="menu-down" />
</button>
</div>
</div>
@@ -65,6 +67,9 @@
<b-tag type="is-info" v-if="event.visibility === EventVisibility.PUBLIC">{{ $t('Public event') }}</b-tag>
<b-tag type="is-info" v-if="event.visibility === EventVisibility.UNLISTED">{{ $t('Private event') }}</b-tag>
</span>
<span v-if="!event.local">
<b-tag type="is-primary">{{ event.organizerActor.domain }}</b-tag>
</span>
<router-link
v-if="event.tags && event.tags.length > 0"
v-for="tag in event.tags"
@@ -136,7 +141,7 @@
</b-modal>
</div>
<span class="online-address" v-if="event.onlineAddress && urlToHostname(event.onlineAddress)">
<b-icon icon="link"></b-icon>
<b-icon icon="link" />
<a
target="_blank"
rel="noopener noreferrer"
@@ -250,8 +255,14 @@
</template>
<script lang="ts">
import { EVENT_PERSON_PARTICIPATION, FETCH_EVENT, JOIN_EVENT, LEAVE_EVENT } from '@/graphql/event';
import { Component, Prop } from 'vue-property-decorator';
import {
EVENT_PERSON_PARTICIPATION,
EVENT_PERSON_PARTICIPATION_SUBSCRIPTION_CHANGED,
FETCH_EVENT,
JOIN_EVENT,
LEAVE_EVENT,
} from '@/graphql/event';
import { Component, Prop, Watch } from 'vue-property-decorator';
import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
import { EventModel, EventStatus, EventVisibility, IEvent, IParticipant, ParticipantRole } from '@/types/event.model';
import { IPerson, Person } from '@/types/actor';
@@ -311,6 +322,15 @@ import 'intersection-observer';
actorId: this.currentActor.id,
};
},
subscribeToMore: {
document: EVENT_PERSON_PARTICIPATION_SUBSCRIPTION_CHANGED,
variables() {
return {
eventId: this.event.id,
actorId: this.currentActor.id,
};
},
},
update: (data) => {
if (data && data.person) return data.person.participations;
return [];
@@ -341,6 +361,7 @@ export default class Event extends EventMixin {
currentActor!: IPerson;
identity: IPerson = new Person();
participations: IParticipant[] = [];
oldParticipationRole!: String;
showMap: boolean = false;
isReportModalActive: boolean = false;
isJoinModalActive: boolean = false;
@@ -432,14 +453,10 @@ export default class Event extends EventMixin {
reporterId: this.currentActor.id,
reportedId: this.event.organizerActor.id,
content,
forward,
},
});
this.$buefy.notification.open({
message: this.$t('Event {eventTitle} reported', { eventTitle }) as string,
type: 'is-success',
position: 'is-bottom-right',
duration: 5000,
});
this.$notifier.success(this.$t('Event {eventTitle} reported', { eventTitle }) as string);
} catch (error) {
console.error(error);
}
@@ -493,12 +510,11 @@ export default class Event extends EventMixin {
},
});
if (data) {
this.$buefy.notification.open({
message: (data.joinEvent.role === ParticipantRole.NOT_APPROVED ? this.$t('Your participation has been requested') : this.$t('Your participation has been confirmed')) as string,
type: 'is-success',
position: 'is-bottom-right',
duration: 5000,
});
if (data.joinEvent.role === ParticipantRole.NOT_APPROVED) {
this.participationRequestedMessage();
} else {
this.participationConfirmedMessage();
}
}
} catch (error) {
console.error(error);
@@ -563,18 +579,55 @@ export default class Event extends EventMixin {
},
});
if (data) {
this.$buefy.notification.open({
message: this.$t('You have cancelled your participation') as string,
type: 'is-success',
position: 'is-bottom-right',
duration: 5000,
});
this.participationCancelledMessage();
}
} catch (error) {
console.error(error);
}
}
@Watch('participations')
watchParticipations() {
if (this.participations.length > 0) {
if (this.oldParticipationRole
&& this.participations[0].role !== ParticipantRole.NOT_APPROVED
&& this.oldParticipationRole !== this.participations[0].role) {
switch (this.participations[0].role) {
case ParticipantRole.PARTICIPANT:
this.participationConfirmedMessage();
break;
case ParticipantRole.REJECTED:
this.participationRejectedMessage();
break;
default:
this.participationChangedMessage();
break;
}
}
this.oldParticipationRole = this.participations[0].role;
}
}
private participationConfirmedMessage() {
this.$notifier.success(this.$t('Your participation has been confirmed') as string);
}
private participationRequestedMessage() {
this.$notifier.success(this.$t('Your participation has been requested') as string);
}
private participationRejectedMessage() {
this.$notifier.error(this.$t('Your participation has been rejected') as string);
}
private participationChangedMessage() {
this.$notifier.info(this.$t('Your participation status has been changed') as string);
}
private participationCancelledMessage() {
this.$notifier.success(this.$t('You have cancelled your participation') as string);
}
async downloadIcsEvent() {
const data = await (await fetch(`${GRAPHQL_API_ENDPOINT}/events/${this.uuid}/export/ics`)).text();
const blob = new Blob([data], { type: 'text/calendar' });