Merge branch 'front-fixes' into 'master'
Front-end fixes and updates See merge request framasoft/mobilizon!80
This commit is contained in:
commit
a83f214f28
1581
js/package-lock.json
generated
1581
js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,8 +13,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-absinthe-upload-link": "^1.5.0",
|
||||
"apollo-cache-inmemory": "^1.4.2",
|
||||
"apollo-client": "^2.4.12",
|
||||
"apollo-cache-inmemory": "^1.4.3",
|
||||
"apollo-client": "^2.4.13",
|
||||
"apollo-link": "^1.2.8",
|
||||
"apollo-link-http": "^1.5.11",
|
||||
"apollo-link-state": "^0.4.2",
|
||||
@ -25,37 +25,37 @@
|
||||
"lodash": "^4.17.11",
|
||||
"material-design-icons": "^3.0.1",
|
||||
"ngeohash": "^0.6.3",
|
||||
"register-service-worker": "^1.6.1",
|
||||
"vue": "^2.6.3",
|
||||
"register-service-worker": "^1.6.2",
|
||||
"vue": "^2.6.7",
|
||||
"vue-apollo": "^3.0.0-beta.28",
|
||||
"vue-class-component": "^6.3.2",
|
||||
"vue-class-component": "^7.0.1",
|
||||
"vue-gettext": "^2.1.2",
|
||||
"vue-markdown": "^2.2.4",
|
||||
"vue-property-decorator": "^7.3.0",
|
||||
"vue-router": "^3.0.2",
|
||||
"vue-simple-markdown": "^1.0.8",
|
||||
"vuex": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/lodash": "^4.14.120",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@vue/cli-plugin-babel": "^3.4.0",
|
||||
"@vue/cli-plugin-e2e-nightwatch": "^3.4.0",
|
||||
"@vue/cli-plugin-pwa": "^3.4.0",
|
||||
"@vue/cli-plugin-typescript": "^3.4.0",
|
||||
"@vue/cli-plugin-unit-mocha": "^3.4.0",
|
||||
"@vue/cli-service": "^3.4.0",
|
||||
"@types/lodash": "^4.14.121",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@vue/cli-plugin-babel": "^3.4.1",
|
||||
"@vue/cli-plugin-e2e-nightwatch": "^3.4.1",
|
||||
"@vue/cli-plugin-pwa": "^3.4.1",
|
||||
"@vue/cli-plugin-typescript": "^3.4.1",
|
||||
"@vue/cli-plugin-unit-mocha": "^3.4.1",
|
||||
"@vue/cli-service": "^3.4.1",
|
||||
"@vue/eslint-config-typescript": "^4.0.0",
|
||||
"@vue/test-utils": "^1.0.0-beta.29",
|
||||
"chai": "^4.2.0",
|
||||
"dotenv-webpack": "^1.7.0",
|
||||
"node-sass": "^4.11.0",
|
||||
"patch-package": "^6.0.2",
|
||||
"patch-package": "^6.0.4",
|
||||
"sass-loader": "^7.1.0",
|
||||
"tslint-config-airbnb": "^5.11.1",
|
||||
"typescript": "^3.3.3",
|
||||
"vue-template-compiler": "^2.6.3",
|
||||
"webpack-bundle-analyzer": "^3.0.3"
|
||||
"typescript": "^3.3.3333",
|
||||
"vue-template-compiler": "^2.6.7",
|
||||
"webpack-bundle-analyzer": "^3.0.4"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
|
@ -5,7 +5,8 @@ const participantQuery = `
|
||||
actor {
|
||||
preferredUsername,
|
||||
avatarUrl,
|
||||
name
|
||||
name,
|
||||
id
|
||||
}
|
||||
`;
|
||||
|
||||
@ -117,23 +118,20 @@ export const EDIT_EVENT = gql`
|
||||
`;
|
||||
|
||||
export const JOIN_EVENT = gql`
|
||||
mutation JoinEvent($id: Int!, $actorId: Int!) {
|
||||
mutation JoinEvent($eventId: Int!, $actorId: Int!) {
|
||||
joinEvent(
|
||||
id: $id,
|
||||
eventId: $eventId,
|
||||
actorId: $actorId
|
||||
) {
|
||||
actor {
|
||||
${participantQuery}
|
||||
},
|
||||
role
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const LEAVE_EVENT = gql`
|
||||
mutation LeaveEvent($id: Int!, $actorId: Int!) {
|
||||
mutation LeaveEvent($eventId: Int!, $actorId: Int!) {
|
||||
leaveEvent(
|
||||
id: $id,
|
||||
eventId: $eventId,
|
||||
actorId: $actorId
|
||||
) {
|
||||
actor {
|
||||
|
@ -2,7 +2,7 @@
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
import Vue from 'vue';
|
||||
// import * as VueGoogleMaps from 'vue2-google-maps';
|
||||
import VueMarkdown from 'vue-markdown';
|
||||
import VueSimpleMarkdown from 'vue-simple-markdown';
|
||||
import Buefy from 'buefy'
|
||||
import 'buefy/dist/buefy.css';
|
||||
import GetTextPlugin from 'vue-gettext';
|
||||
@ -14,7 +14,7 @@ const translations = require('@/i18n/translations.json');
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
Vue.use(VueMarkdown);
|
||||
Vue.use(VueSimpleMarkdown);
|
||||
Vue.use(Buefy, {
|
||||
defaultContainerElement: '#mobilizon'
|
||||
});
|
||||
|
@ -28,7 +28,8 @@ export const userRoutes = [
|
||||
path: '/register/profile',
|
||||
name: UserRouteName.REGISTER_PROFILE,
|
||||
component: RegisterProfile,
|
||||
props: true,
|
||||
// We can only pass string values through params, therefore
|
||||
props: (route) => ({ email: route.params.email, userAlreadyActivated: route.params.userAlreadyActivated === 'true' }),
|
||||
meta: { requiredAuth: false },
|
||||
},
|
||||
{
|
||||
@ -56,8 +57,7 @@ export const userRoutes = [
|
||||
path: '/validate/:token',
|
||||
name: UserRouteName.VALIDATE,
|
||||
component: Validate,
|
||||
// We can only pass string values through params, therefore
|
||||
props: (route) => ({ email: route.params.email, userAlreadyActivated: route.params.userAlreadyActivated === 'true' }),
|
||||
props: true,
|
||||
meta: { requiresAuth: false },
|
||||
},
|
||||
{
|
||||
|
@ -12,16 +12,6 @@
|
||||
<div class="columns is-mobile">
|
||||
<div class="column">
|
||||
<form v-if="!validationSent">
|
||||
<div class="columns is-mobile is-centered">
|
||||
<div class="column is-narrow">
|
||||
<figure class="image is-64x64">
|
||||
<transition name="avatar">
|
||||
<v-gravatar v-bind="{email: email}" default-img="mp"></v-gravatar>
|
||||
</transition>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-field
|
||||
:label="$gettext('Username')"
|
||||
:type="errors.preferred_username ? 'is-danger' : null"
|
||||
|
@ -34,18 +34,13 @@ import {EventJoinOptions} from "../../types/event.model";
|
||||
|
||||
<script lang="ts">
|
||||
// import Location from '@/components/Location';
|
||||
import VueMarkdown from "vue-markdown";
|
||||
import {CREATE_EVENT, EDIT_EVENT} from "@/graphql/event";
|
||||
import {Component, Prop, Vue} from "vue-property-decorator";
|
||||
import {Category, EventJoinOptions, EventStatus, EventVisibility, IEvent} from "@/types/event.model";
|
||||
import {LOGGED_PERSON} from "@/graphql/actor";
|
||||
import {IPerson} from "@/types/actor.model";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VueMarkdown
|
||||
}
|
||||
})
|
||||
@Component({})
|
||||
export default class CreateEvent extends Vue {
|
||||
@Prop({ required: false, type: String }) uuid!: string;
|
||||
|
||||
|
@ -47,15 +47,22 @@
|
||||
<span>{{ event.begins_on | formatDate }} - {{ event.ends_on | formatDate }}</span>
|
||||
</div>
|
||||
<p v-if="actorIsOrganizer()">
|
||||
<translate>Vous êtes organisateur de cet événement.</translate>
|
||||
<translate>You are an organizer.</translate>
|
||||
</p>
|
||||
<div v-else>
|
||||
<p v-if="actorIsParticipant()">
|
||||
<translate>Vous avez annoncé aller à cet événement.</translate>
|
||||
<translate>You announced that you're going to this event.</translate>
|
||||
</p>
|
||||
<p v-else>
|
||||
Vous y allez ?
|
||||
<span>{{ event.participants.length }} personnes y vont.</span>
|
||||
<translate>Are you going to this event?</translate><br />
|
||||
<span>
|
||||
<translate
|
||||
:translate-n="event.participants.length"
|
||||
translate-plural="%{event.participants.length} persons are going"
|
||||
>
|
||||
One person is going.
|
||||
</translate>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="!actorIsOrganizer()">
|
||||
@ -66,7 +73,7 @@
|
||||
</div>
|
||||
<h2 class="subtitle">Details</h2>
|
||||
<p v-if="event.description">
|
||||
<vue-markdown :source="event.description"></vue-markdown>
|
||||
<vue-simple-markdown :source="event.description"></vue-simple-markdown>
|
||||
</p>
|
||||
<h2 class="subtitle">Participants</h2>
|
||||
<span v-if="event.participants.length === 0">No participants yet.</span>
|
||||
@ -99,15 +106,10 @@ 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';
|
||||
import { RouteName } from '@/router'
|
||||
|
||||
// No typings for this component, so we use require
|
||||
const VueMarkdown = require('vue-markdown');
|
||||
import { RouteName } from '@/router';
|
||||
import 'vue-simple-markdown/dist/vue-simple-markdown.css';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VueMarkdown
|
||||
},
|
||||
apollo: {
|
||||
event: {
|
||||
query: FETCH_EVENT,
|
||||
@ -152,13 +154,13 @@ export default class Event extends Vue {
|
||||
await this.$apollo.mutate<IParticipant>({
|
||||
mutation: JOIN_EVENT,
|
||||
variables: {
|
||||
id: this.event.id,
|
||||
eventId: 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.')
|
||||
console.error('Cannot update event participant cache, because of null value.');
|
||||
return
|
||||
}
|
||||
|
||||
@ -177,7 +179,7 @@ export default class Event extends Vue {
|
||||
await this.$apollo.mutate<IParticipant>({
|
||||
mutation: LEAVE_EVENT,
|
||||
variables: {
|
||||
id: this.event.id,
|
||||
eventId: this.event.id,
|
||||
actorId: this.loggedPerson.id,
|
||||
},
|
||||
update: (store, { data: { leaveEvent } }) => {
|
||||
|
@ -19,17 +19,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import ngeohash from 'ngeohash';
|
||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||
import EventCard from '@/components/Event/EventCard.vue';
|
||||
import { RouteName } from '@/router';
|
||||
|
||||
// VueMarkdown is untyped
|
||||
const VueMarkdown = require('vue-markdown');
|
||||
const ngeohash = require('ngeohash');
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VueMarkdown,
|
||||
EventCard
|
||||
}
|
||||
})
|
||||
|
@ -28,14 +28,7 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
|
||||
// VueMarkdown is untyped
|
||||
const VueMarkdown = require('vue-markdown')
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VueMarkdown
|
||||
}
|
||||
})
|
||||
@Component({})
|
||||
export default class CreateGroup extends Vue {
|
||||
e1 = 0;
|
||||
// FIXME: correctly type group
|
||||
|
@ -4,7 +4,7 @@ defmodule MobilizonWeb.Resolvers.Event do
|
||||
"""
|
||||
alias Mobilizon.Activity
|
||||
alias Mobilizon.Events.{Event, Participant}
|
||||
alias Mobilizon.Actors.User
|
||||
alias Mobilizon.Actors.{User, Actor}
|
||||
|
||||
# We limit the max number of events that can be retrieved
|
||||
@event_max_limit 100
|
||||
@ -100,8 +100,7 @@ defmodule MobilizonWeb.Resolvers.Event do
|
||||
{:ok, %Participant{} = participant} <-
|
||||
Mobilizon.Events.get_participant(event_id, actor_id),
|
||||
{:only_organizer, false} <-
|
||||
{:only_organizer,
|
||||
Mobilizon.Events.list_organizers_participants_for_event(event_id) |> length == 1},
|
||||
{:only_organizer, check_that_participant_is_not_only_organizer(event_id, actor_id)},
|
||||
{:ok, _} <-
|
||||
Mobilizon.Events.delete_participant(participant) do
|
||||
{:ok, %{event: %{id: event_id}, actor: %{id: actor_id}}}
|
||||
@ -121,6 +120,19 @@ defmodule MobilizonWeb.Resolvers.Event do
|
||||
{:error, "You need to be logged-in to leave an event"}
|
||||
end
|
||||
|
||||
# We check that the actor asking to leave the event is not it's only organizer
|
||||
# We start by fetching the list of organizers and if there's only one of them
|
||||
# and that it's the actor requesting leaving the event we return true
|
||||
@spec check_that_participant_is_not_only_organizer(integer(), integer()) :: boolean()
|
||||
defp check_that_participant_is_not_only_organizer(event_id, actor_id) do
|
||||
with [%Participant{actor: %Actor{id: participant_actor_id}}] <-
|
||||
Mobilizon.Events.list_organizers_participants_for_event(event_id) do
|
||||
participant_actor_id == actor_id
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create an event
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user