Add draft feature

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2019-10-02 17:59:07 +02:00
parent b96f3bc3ad
commit 442a011490
22 changed files with 587 additions and 66 deletions

View File

@@ -9,7 +9,7 @@
</h1>
<div class="columns is-centered">
<form class="column is-two-thirds-desktop">
<form class="column is-two-thirds-desktop" ref="form">
<h2 class="subtitle">
{{ $t('General information') }}
</h2>
@@ -170,14 +170,16 @@
{{ $t('Cancel') }}
</b-button>
</span>
<span class="navbar-item" v-if="isUpdate === false">
<b-button type="is-primary" outlined>
<!-- If an event has been published we can't make it draft anymore -->
<span class="navbar-item" v-if="event.draft === true">
<b-button type="is-primary" outlined @click="createOrUpdateDraft">
{{ $t('Save draft') }}
</b-button>
</span>
<span class="navbar-item">
<b-button type="is-primary" @click="createOrUpdate" @keyup.enter="createOrUpdate">
<b-button type="is-primary" @click="createOrUpdatePublish" @keyup.enter="createOrUpdatePublish">
<span v-if="isUpdate === false">{{ $t('Create my event') }}</span>
<span v-else-if="event.draft === true"> {{ $t('Publish') }}</span>
<span v-else> {{ $t('Update my event') }}</span>
</b-button>
</span>
@@ -238,7 +240,7 @@ import {
EventVisibility, IEvent,
} from '@/types/event.model';
import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
import { Person } from '@/types/actor';
import { IActor, Person } from '@/types/actor';
import PictureUpload from '@/components/PictureUpload.vue';
import Editor from '@/components/Editor.vue';
import DateTimePicker from '@/components/Event/DateTimePicker.vue';
@@ -312,7 +314,6 @@ export default class EditEvent extends Vue {
this.observer = new IntersectionObserver((entries, observer) => {
for (const entry of entries) {
if (entry) {
console.log(entry);
this.showFixedNavbar = !entry.isIntersecting;
}
}
@@ -322,12 +323,29 @@ export default class EditEvent extends Vue {
this.observer.observe(this.$refs.bottomObserver as Element);
}
createOrUpdate(e: Event) {
createOrUpdateDraft(e: Event) {
e.preventDefault();
if (this.validateForm()) {
if (this.eventId) return this.updateEvent();
if (this.eventId) return this.updateEvent();
return this.createEvent();
}
}
return this.createEvent();
createOrUpdatePublish(e: Event) {
if (this.validateForm()) {
this.event.draft = false;
this.createOrUpdateDraft(e);
}
}
private validateForm() {
const form = this.$refs.form as HTMLFormElement;
if (form.checkValidity()) {
return true;
}
form.reportValidity();
return false;
}
async createEvent() {
@@ -412,13 +430,16 @@ export default class EditEvent extends Vue {
* Confirm cancel
*/
confirmGoBack() {
if (!this.isEventModified) {
return this.$router.go(-1);
}
const title: string = this.isUpdate ?
this.$t('Cancel edition') as string :
this.$t('Cancel creation') as string;
const message: string = this.isUpdate ?
this.$t('Are you sure you want to cancel the event edition? You\'ll lose all modifications.',
this.$t("Are you sure you want to cancel the event edition? You'll lose all modifications.",
{ title: this.event.title }) as string :
this.$t('Are you sure you want to cancel the event creation? You\'ll lose all modifications.',
this.$t("Are you sure you want to cancel the event creation? You'll lose all modifications.",
{ title: this.event.title }) as string;
this.$buefy.dialog.confirm({

View File

@@ -18,15 +18,15 @@
</div>
<h1 class="title">{{ event.title }}</h1>
</div>
<div class="has-text-right">
<div class="has-text-right" v-if="new Date(endDate) > new Date()">
<small v-if="event.participantStats.approved > 0 && !actorIsParticipant">
{{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }}
</small>
<small v-else>
<small v-else-if="event.participantStats.approved > 0 && actorIsParticipant">
{{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
</small>
<participation-button
v-if="currentActor.id && !actorIsOrganizer"
v-if="currentActor.id && !actorIsOrganizer && !event.draft"
:participation="participations[0]"
:current-actor="currentActor"
@joinEvent="joinEvent"
@@ -34,15 +34,25 @@
@confirmLeave="confirmLeave"
/>
</div>
<div v-else>
<button class="button is-primary" type="button" slot="trigger" disabled>
<template>
<span>{{ $t('Event already passed')}}</span>
</template>
<b-icon icon="menu-down"></b-icon>
</button>
</div>
</div>
<div class="metadata columns">
<div class="column is-three-quarters-desktop">
<p class="tags" v-if="event.category || event.tags.length > 0">
<b-tag type="is-warning" size="is-medium" v-if="event.draft">{{ $t('Draft') }}</b-tag>
<!-- <span class="tag" v-if="event.category">{{ event.category }}</span>-->
<span class="tag" v-if="event.tags" v-for="tag in event.tags">{{ tag.title }}</span>
<span class="visibility">
<span v-if="event.visibility === EventVisibility.PUBLIC">{{ $t('Public event') }}</span>
<span v-if="event.visibility === EventVisibility.UNLISTED">{{ $t('Private event') }}</span>
<b-tag type="is-success" v-if="event.tags" v-for="tag in event.tags">{{ tag.title }}</b-tag>
<span v-if="event.tags > 0"></span>
<span class="visibility" v-if="!event.draft">
<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>
</p>
<div class="date-and-add-to-calendar">
@@ -50,7 +60,7 @@
<b-icon icon="calendar-clock" />
<event-full-date :beginsOn="event.beginsOn" :endsOn="event.endsOn" />
</div>
<a class="add-to-calendar" @click="downloadIcsEvent()">
<a class="add-to-calendar" @click="downloadIcsEvent()" v-if="!event.draft">
<b-icon icon="calendar-plus" />
{{ $t('Add to my calendar') }}
</a>
@@ -61,7 +71,7 @@
</div>
<div class="column sidebar">
<div class="field has-addons" v-if="currentActor.id">
<p class="control" v-if="actorIsOrganizer">
<p class="control" v-if="actorIsOrganizer || event.draft">
<router-link
class="button"
:to="{ name: 'EditEvent', params: {eventId: event.uuid}}"
@@ -69,7 +79,7 @@
{{ $t('Edit') }}
</router-link>
</p>
<p class="control" v-if="actorIsOrganizer">
<p class="control" v-if="actorIsOrganizer || event.draft">
<a class="button is-danger" @click="openDeleteEventModalWrapper">
{{ $t('Delete') }}
</a>
@@ -133,7 +143,7 @@
</div>
</div>
</div>
<section class="share">
<section class="share" v-if="!event.draft">
<div class="container">
<div class="columns">
<div class="column is-half has-text-centered">
@@ -433,6 +443,10 @@ export default class Event extends EventMixin {
return this.participations.length > 0 && this.participations[0].role === ParticipantRole.CREATOR;
}
get endDate() {
return this.event.endsOn !== null && this.event.endsOn > this.event.beginsOn ? this.event.endsOn : this.event.beginsOn;
}
get twitterShareUrl(): string {
return `https://twitter.com/intent/tweet?url=${encodeURIComponent(this.event.url)}&text=${this.event.title}`;
}
@@ -597,18 +611,14 @@ export default class Event extends EventMixin {
p.tags {
span {
&.tag {
&.tag.is-success {
&::before {
content: '#';
}
text-transform: uppercase;
color: #111111;
}
&.visibility::before {
content: "⋅"
}
margin: auto 5px;
}
margin-bottom: 1rem;

View File

@@ -26,6 +26,19 @@
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">
<h2 class="subtitle">
{{ $t('Drafts') }}
</h2>
<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">
<h2 class="subtitle">
{{ $t('Past events') }}
@@ -56,13 +69,15 @@
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { LOGGED_USER_PARTICIPATIONS } from '@/graphql/actor';
import { IParticipant, Participant } from '@/types/event.model';
import { LOGGED_USER_PARTICIPATIONS, LOGGED_USER_DRAFTS } from '@/graphql/actor';
import { EventModel, IEvent, IParticipant, Participant } from '@/types/event.model';
import EventListCard from '@/components/Event/EventListCard.vue';
import EventCard from '@/components/Event/EventCard.vue';
@Component({
components: {
EventCard,
EventListCard,
},
apollo: {
@@ -75,6 +90,14 @@ import EventListCard from '@/components/Event/EventListCard.vue';
},
update: data => data.loggedUser.participations.map(participation => new Participant(participation)),
},
drafts: {
query: LOGGED_USER_DRAFTS,
variables: {
page: 1,
limit: 10,
},
update: data => data.loggedUser.drafts.map(event => new EventModel(event)),
},
pastParticipations: {
query: LOGGED_USER_PARTICIPATIONS,
variables: {
@@ -97,6 +120,8 @@ export default class MyEvents extends Vue {
pastParticipations: IParticipant[] = [];
hasMorePastParticipations: boolean = true;
drafts: IEvent[] = [];
private monthlyParticipations(participations: IParticipant[]): Map<string, Participant[]> {
const res = participations.filter(({ event }) => event.beginsOn != null);
res.sort(