Merge branch 'feature/cleanup-event' into 'master'

Add leave/join/delete event logic

See merge request framasoft/mobilizon!74
This commit is contained in:
Thomas Citharel 2019-02-22 13:54:50 +01:00
commit 24dfa3b2d1
5 changed files with 327 additions and 261 deletions

View File

@ -1,5 +1,14 @@
import gql from 'graphql-tag';
const participantQuery = `
role,
actor {
preferredUsername,
avatarUrl,
name
}
`;
export const FETCH_EVENT = gql`
query($uuid:UUID!) {
event(uuid: $uuid) {
@ -29,12 +38,7 @@ export const FETCH_EVENT = gql`
# name,
# },
participants {
actor {
avatarUrl,
preferredUsername,
name,
},
role,
${participantQuery}
},
category {
title,
@ -75,12 +79,7 @@ export const FETCH_EVENTS = gql`
title,
},
participants {
role,
actor {
preferredUsername,
avatarUrl,
name
}
${participantQuery}
}
}
}
@ -122,13 +121,37 @@ export const EDIT_EVENT = gql`
`;
export const JOIN_EVENT = gql`
mutation JoinEvent(
$uuid: String!,
$username: String!
) {
mutation JoinEvent($id: Int!, $actorId: Int!) {
joinEvent(
uuid: $uuid,
username: $username
id: $id,
actorId: $actorId
) {
actor {
${participantQuery}
},
role
}
}
`;
export const LEAVE_EVENT = gql`
mutation LeaveEvent($id: Int!, $actorId: Int!) {
leaveEvent(
id: $id,
actorId: $actorId
) {
actor {
id
}
}
}
`;
export const DELETE_EVENT = gql`
mutation DeleteEvent($id: Int!, $actorId: Int!) {
deleteEvent(
id: $id,
actorId: $actorId
)
}
`;

View File

@ -19,7 +19,10 @@ export interface IGroup extends IActor {
}
export enum MemberRole {
PENDING, MEMBER, MODERATOR, ADMIN
PENDING,
MEMBER,
MODERATOR,
ADMIN,
}
export interface IMember {

View File

@ -1,30 +1,30 @@
import { IActor } from "./actor.model";
import { IActor } from './actor.model';
export enum EventStatus {
TENTATIVE,
CONFIRMED,
CANCELLED
CANCELLED,
}
export enum EventVisibility {
PUBLIC,
UNLISTED,
RESTRICTED,
PRIVATE
PRIVATE,
}
export enum EventJoinOptions {
FREE,
RESTRICTED,
INVITE
INVITE,
}
export enum ParticipantRole {
NOT_APPROVED = 'not_approved',
PARTICIPANT = 'participant',
MODERATOR = 'moderator',
ADMINSTRATOR = 'administrator',
CREATOR = 'creator'
ADMINISTRATOR = 'administrator',
CREATOR = 'creator',
}
export interface ICategory {
@ -34,29 +34,37 @@ export interface ICategory {
}
export interface IParticipant {
role: ParticipantRole,
actor: IActor,
event: IEvent
role: ParticipantRole;
actor: IActor;
event: IEvent;
}
export interface IEvent {
id?: number;
uuid: string;
url: string;
local: boolean;
title: string;
description: string;
category: ICategory;
begins_on: Date;
ends_on: Date;
publish_at: Date;
status: EventStatus;
visibility: EventVisibility;
join_options: EventJoinOptions;
thumbnail: string;
large_image: string;
publish_at: Date;
// online_address: Adress;
// phone_address: string;
organizerActor: IActor;
attributedTo: IActor;
participants: IParticipant[];
category: ICategory;
// online_address: Address;
// phone_address: string;
}

View File

@ -93,13 +93,15 @@
</template>
<script lang="ts">
import { FETCH_EVENT } from "@/graphql/event";
import { Component, Prop, Vue } from "vue-property-decorator";
import VueMarkdown from "vue-markdown";
import { LOGGED_PERSON } from "../../graphql/actor";
import { IEvent } from "@/types/event.model";
import { JOIN_EVENT } from "../../graphql/event";
import { IPerson } from "@/types/actor.model";
import { DELETE_EVENT, FETCH_EVENT, LEAVE_EVENT } from '@/graphql/event';
import { Component, Prop, Vue } from 'vue-property-decorator';
import { LOGGED_PERSON } from '@/graphql/actor';
import { IEvent, IParticipant } from '@/types/event.model';
import { JOIN_EVENT } from '@/graphql/event';
import { IPerson } from '@/types/actor.model';
// No typings for this component, so we use require
const VueMarkdown = require('vue-markdown');
@Component({
components: {
@ -126,31 +128,73 @@ export default class Event extends Vue {
loggedPerson!: IPerson;
validationSent: boolean = false;
deleteEvent() {
async deleteEvent() {
const router = this.$router;
// FIXME: remove eventFetch
// eventFetch(`/events/${this.uuid}`, this.$store, { method: 'DELETE' })
// .then(() => router.push({ name: 'EventList' }));
try {
await this.$apollo.mutate<IParticipant>({
mutation: DELETE_EVENT,
variables: {
id: this.event.id,
actorId: this.loggedPerson.id,
}
});
router.push({ name: 'EventList' })
} catch (error) {
console.error(error);
}
}
async joinEvent() {
try {
this.validationSent = true;
await this.$apollo.mutate({
mutation: JOIN_EVENT
await this.$apollo.mutate<IParticipant>({
mutation: JOIN_EVENT,
variables: {
id: this.event.id,
actorId: this.loggedPerson.id,
},
update: (store, { data: { joinEvent } }) => {
const event = store.readQuery<IEvent>({ query: FETCH_EVENT });
if (event === null) {
console.error('Cannot update event participant cache, because of null value.')
return
}
event.participants = event.participants.concat([ joinEvent ]);
store.writeQuery({ query: FETCH_EVENT, data: event });
}
});
} catch (error) {
console.error(error);
}
}
leaveEvent() {
// FIXME: remove eventFetch
// eventFetch(`/events/${this.uuid}/leave`, this.$store)
// .then(response => response.json())
// .then((data) => {
// console.log(data);
// });
async leaveEvent() {
try {
await this.$apollo.mutate<IParticipant>({
mutation: LEAVE_EVENT,
variables: {
id: this.event.id,
actorId: this.loggedPerson.id,
},
update: (store, { data: { leaveEvent } }) => {
const event = store.readQuery<IEvent>({ query: FETCH_EVENT });
if (event === null) {
console.error('Cannot update event participant cache, because of null value.');
return
}
event.participants = event.participants
.filter(p => p.actor.id !== leaveEvent.actor.id);
store.writeQuery({ query: FETCH_EVENT, data: event });
}
});
} catch (error) {
console.error(error);
}
}
downloadIcsEvent() {
@ -169,28 +213,16 @@ export default class Event extends Vue {
}
actorIsParticipant() {
return (
(this.loggedPerson &&
if (this.actorIsOrganizer()) return true;
return this.loggedPerson &&
this.event.participants
.map(participant => participant.actor.preferredUsername)
.includes(this.loggedPerson.preferredUsername)) ||
this.actorIsOrganizer()
);
.some(participant => participant.actor.id === this.loggedPerson.id);
}
//
actorIsOrganizer() {
return (
this.loggedPerson &&
this.loggedPerson.preferredUsername ===
this.event.organizerActor.preferredUsername
);
return this.loggedPerson &&
this.loggedPerson.id === this.event.organizerActor.id;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.v-card__media__background {
filter: contrast(0.4);
}
</style>