Merge branch 'master' into refactoring-based-on-credo-and-dialyzer
This commit is contained in:
commit
4c74248a04
@ -12,7 +12,7 @@ config :mobilizon, MobilizonWeb.Endpoint,
|
||||
],
|
||||
url: [
|
||||
host: System.get_env("MOBILIZON_INSTANCE_HOST") || "mobilizon.local",
|
||||
port: 80,
|
||||
port: System.get_env("MOBILIZON_INSTANCE_PORT") || 4000,
|
||||
scheme: "http"
|
||||
],
|
||||
debug_errors: true,
|
||||
|
58
js/Makefile
58
js/Makefile
@ -1,58 +0,0 @@
|
||||
# On OSX the PATH variable isn't exported unless "SHELL" is also set, see: http://stackoverflow.com/a/25506676
|
||||
SHELL = /bin/bash
|
||||
NODE_BINDIR = ./node_modules/.bin
|
||||
export PATH := $(NODE_BINDIR):$(PATH)
|
||||
|
||||
# Where to find input files (it can be multiple paths).
|
||||
INPUT_FILES = ./src
|
||||
|
||||
# Where to write the files generated by this makefile.
|
||||
OUTPUT_DIR = ./src/i18n
|
||||
|
||||
# Available locales for the app.
|
||||
LOCALES = en_US fr_FR
|
||||
|
||||
# Name of the generated .po files for each available locale.
|
||||
LOCALE_FILES ?= $(patsubst %,$(OUTPUT_DIR)/locale/%/LC_MESSAGES/app.po,$(LOCALES))
|
||||
|
||||
GETTEXT_HTML_SOURCES = $(shell find $(INPUT_FILES) -name '*.vue' -o -name '*.html' 2> /dev/null)
|
||||
GETTEXT_JS_SOURCES = $(shell find $(INPUT_FILES) -name '*.vue' -o -name '*.js')
|
||||
|
||||
# Makefile Targets
|
||||
.PHONY: clean makemessages translations
|
||||
|
||||
clean:
|
||||
rm -f /tmp/template.pot $(OUTPUT_DIR)/translations.json
|
||||
|
||||
makemessages: /tmp/template.pot
|
||||
|
||||
translations: ./$(OUTPUT_DIR)/translations.json
|
||||
|
||||
# Create a main .pot template, then generate .po files for each available language.
|
||||
# Thanx to Systematic: https://github.com/Polyconseil/systematic/blob/866d5a/mk/main.mk#L167-L183
|
||||
/tmp/template.pot: $(GETTEXT_HTML_SOURCES)
|
||||
# `dir` is a Makefile built-in expansion function which extracts the directory-part of `$@`.
|
||||
# `$@` is a Makefile automatic variable: the file name of the target of the rule.
|
||||
# => `mkdir -p /tmp/`
|
||||
mkdir -p $(dir $@)
|
||||
which gettext-extract
|
||||
# Extract gettext strings from templates files and create a POT dictionary template.
|
||||
gettext-extract --attribute v-translate --quiet --parseScript false --output $@ $(GETTEXT_HTML_SOURCES)
|
||||
# Extract gettext strings from JavaScript files.
|
||||
xgettext --language=JavaScript --keyword=npgettext:1c,2,3 \
|
||||
--from-code=utf-8 --join-existing --no-wrap \
|
||||
--package-name=$(shell node -e "console.log(require('./package.json').name);") \
|
||||
--package-version=$(shell node -e "console.log(require('./package.json').version);") \
|
||||
--output $@ $(GETTEXT_JS_SOURCES)
|
||||
# Generate .po files for each available language.
|
||||
@for lang in $(LOCALES); do \
|
||||
export PO_FILE=$(OUTPUT_DIR)/locale/$$lang/LC_MESSAGES/app.po; \
|
||||
echo "msgmerge --update $$PO_FILE $@"; \
|
||||
mkdir -p $$(dirname $$PO_FILE); \
|
||||
[ -f $$PO_FILE ] && msgmerge --lang=$$lang --update $$PO_FILE $@ || msginit --no-translator --locale=$$lang --input=$@ --output-file=$$PO_FILE; \
|
||||
msgattrib --no-wrap --no-obsolete -o $$PO_FILE $$PO_FILE; \
|
||||
done;
|
||||
|
||||
$(OUTPUT_DIR)/translations.json: clean /tmp/template.pot
|
||||
mkdir -p $(OUTPUT_DIR)
|
||||
gettext-compile --output $@ $(LOCALE_FILES)
|
@ -9,7 +9,7 @@
|
||||
"dev": "vue-cli-service build --watch",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"prepare": "patch-package"
|
||||
"vue-i18n-extract": "vue-i18n-extract"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-absinthe-upload-link": "^1.5.0",
|
||||
@ -18,7 +18,6 @@
|
||||
"apollo-link": "^1.2.11",
|
||||
"apollo-link-http": "^1.5.14",
|
||||
"buefy": "^0.8.2",
|
||||
"easygettext": "^2.7.0",
|
||||
"graphql": "^14.2.1",
|
||||
"graphql-tag": "^2.10.1",
|
||||
"leaflet": "^1.4.0",
|
||||
@ -33,7 +32,7 @@
|
||||
"vue": "^2.6.10",
|
||||
"vue-apollo": "^3.0.0-rc.1",
|
||||
"vue-class-component": "^7.0.2",
|
||||
"vue-gettext": "^2.1.3",
|
||||
"vue-i18n": "^8.14.0",
|
||||
"vue-property-decorator": "^8.1.0",
|
||||
"vue-router": "^3.0.6",
|
||||
"vue2-leaflet": "^2.0.3",
|
||||
@ -58,12 +57,12 @@
|
||||
"eslint": "^6.0.1",
|
||||
"graphql-cli": "^3.0.12",
|
||||
"node-sass": "^4.11.0",
|
||||
"patch-package": "^6.1.2",
|
||||
"sass-loader": "^8.0.0",
|
||||
"tslint": "^5.16.0",
|
||||
"tslint-config-airbnb": "^5.11.1",
|
||||
"typescript": "^3.4.3",
|
||||
"vue-cli-plugin-webpack-bundle-analyzer": "^1.3.0",
|
||||
"vue-i18n-extract": "^1.0.2",
|
||||
"vue-svg-inline-loader": "^1.2.15",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.30.0"
|
||||
|
@ -1,41 +0,0 @@
|
||||
patch-package
|
||||
--- a/node_modules/easygettext/src/extract-cli.js
|
||||
+++ b/node_modules/easygettext/src/extract-cli.js
|
||||
@@ -22,9 +22,12 @@ const endDelimiter = argv.endDelimiter === undefined ? constants.DEFAULT_DELIMIT
|
||||
const extraAttribute = argv.attribute || false;
|
||||
const extraFilter = argv.filter || false;
|
||||
const filterPrefix = argv.filterPrefix || constants.DEFAULT_FILTER_PREFIX;
|
||||
+const parseScript = argv.parseScript === undefined ? true : argv.parseScript === 'true';
|
||||
|
||||
if (!quietMode && (!files || files.length === 0)) {
|
||||
- console.log('Usage:\n\tgettext-extract [--attribute EXTRA-ATTRIBUTE] [--filterPrefix FILTER-PREFIX] [--output OUTFILE] <FILES>');
|
||||
+ console.log(
|
||||
+ 'Usage:\n\tgettext-extract [--attribute EXTRA-ATTRIBUTE] [--filterPrefix FILTER-PREFIX] [--parseScript BOOLEAN] [--output OUTFILE] <FILES>',
|
||||
+ );
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -54,7 +57,7 @@ const extractor = new extract.Extractor({
|
||||
});
|
||||
|
||||
|
||||
-files.forEach(function(filename) {
|
||||
+files.forEach(function (filename) {
|
||||
let file = filename;
|
||||
const ext = file.split('.').pop();
|
||||
if (ALLOWED_EXTENSIONS.indexOf(ext) === -1) {
|
||||
@@ -63,9 +66,13 @@ files.forEach(function(filename) {
|
||||
}
|
||||
console.log(`[${PROGRAM_NAME}] extracting: '${filename}`);
|
||||
try {
|
||||
- let data = fs.readFileSync(file, {encoding: 'utf-8'}).toString();
|
||||
+ let data = fs.readFileSync(file, { encoding: 'utf-8' }).toString();
|
||||
extractor.parse(file, extract.preprocessTemplate(data, ext));
|
||||
|
||||
+ if (!parseScript) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (ext !== 'js') {
|
||||
data = extract.preprocessScriptTags(data, ext);
|
||||
}
|
@ -11,11 +11,20 @@
|
||||
<script lang="ts">
|
||||
import NavBar from '@/components/NavBar.vue';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_USER_ACTOR, AUTH_USER_EMAIL, AUTH_USER_ID } from '@/constants';
|
||||
import {
|
||||
AUTH_ACCESS_TOKEN,
|
||||
AUTH_USER_ACTOR_ID,
|
||||
AUTH_USER_EMAIL,
|
||||
AUTH_USER_ID,
|
||||
AUTH_USER_ROLE,
|
||||
} from '@/constants';
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Footer from '@/components/Footer.vue';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import { CURRENT_ACTOR_CLIENT, IDENTITIES, UPDATE_CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { changeIdentity, saveActorData } from '@/utils/auth';
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
@ -30,34 +39,49 @@ import Logo from '@/components/Logo.vue';
|
||||
},
|
||||
})
|
||||
export default class App extends Vue {
|
||||
currentUser!: ICurrentUser;
|
||||
|
||||
actor = localStorage.getItem(AUTH_USER_ACTOR);
|
||||
|
||||
async mounted() {
|
||||
async created() {
|
||||
await this.initializeCurrentUser();
|
||||
}
|
||||
|
||||
getUser(): ICurrentUser | false {
|
||||
return this.currentUser.id ? this.currentUser : false;
|
||||
await this.initializeCurrentActor();
|
||||
}
|
||||
|
||||
private initializeCurrentUser() {
|
||||
const userId = localStorage.getItem(AUTH_USER_ID);
|
||||
const userEmail = localStorage.getItem(AUTH_USER_EMAIL);
|
||||
const accessToken = localStorage.getItem(AUTH_ACCESS_TOKEN);
|
||||
const role = localStorage.getItem(AUTH_USER_ROLE);
|
||||
|
||||
if (userId && userEmail && accessToken) {
|
||||
if (userId && userEmail && accessToken && role) {
|
||||
return this.$apollo.mutate({
|
||||
mutation: UPDATE_CURRENT_USER_CLIENT,
|
||||
variables: {
|
||||
id: userId,
|
||||
email: userEmail,
|
||||
isLoggedIn: true,
|
||||
role,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We fetch from localStorage the latest actor ID used,
|
||||
* then fetch the current identities to set in cache
|
||||
* the current identity used
|
||||
*/
|
||||
private async initializeCurrentActor() {
|
||||
const actorId = localStorage.getItem(AUTH_USER_ACTOR_ID);
|
||||
|
||||
const result = await this.$apollo.query({
|
||||
query: IDENTITIES,
|
||||
});
|
||||
const identities = result.data.identities;
|
||||
if (identities.length < 1) return;
|
||||
const activeIdentity = identities.find(identity => identity.id === actorId) || identities[0] as IPerson;
|
||||
|
||||
if (activeIdentity) {
|
||||
return await changeIdentity(this.$apollo.provider.defaultClient, activeIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -74,6 +98,8 @@ export default class App extends Vue {
|
||||
@import "~bulma/sass/components/navbar.sass";
|
||||
@import "~bulma/sass/components/pagination.sass";
|
||||
@import "~bulma/sass/components/dropdown.sass";
|
||||
@import "~bulma/sass/components/breadcrumb.sass";
|
||||
@import "~bulma/sass/components/list.sass";
|
||||
@import "~bulma/sass/elements/box.sass";
|
||||
@import "~bulma/sass/elements/button.sass";
|
||||
@import "~bulma/sass/elements/container.sass";
|
||||
@ -84,6 +110,7 @@ export default class App extends Vue {
|
||||
@import "~bulma/sass/elements/tag.sass";
|
||||
@import "~bulma/sass/elements/title.sass";
|
||||
@import "~bulma/sass/elements/notification";
|
||||
@import "~bulma/sass/elements/table";
|
||||
@import "~bulma/sass/grid/_all.sass";
|
||||
@import "~bulma/sass/layout/_all.sass";
|
||||
|
||||
@ -100,6 +127,7 @@ export default class App extends Vue {
|
||||
@import "~buefy/src/scss/components/upload";
|
||||
@import "~buefy/src/scss/components/radio";
|
||||
@import "~buefy/src/scss/components/switch";
|
||||
@import "~buefy/src/scss/components/table";
|
||||
|
||||
.router-enter-active,
|
||||
.router-leave-active {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { ApolloCache } from 'apollo-cache';
|
||||
import { NormalizedCacheObject } from 'apollo-cache-inmemory';
|
||||
import { ICurrentUserRole } from '@/types/current-user.model';
|
||||
|
||||
export function buildCurrentUserResolver(cache: ApolloCache<NormalizedCacheObject>) {
|
||||
cache.writeData({
|
||||
@ -9,22 +10,44 @@ export function buildCurrentUserResolver(cache: ApolloCache<NormalizedCacheObjec
|
||||
id: null,
|
||||
email: null,
|
||||
isLoggedIn: false,
|
||||
role: ICurrentUserRole.USER,
|
||||
},
|
||||
currentActor: {
|
||||
__typename: 'CurrentActor',
|
||||
id: null,
|
||||
preferredUsername: null,
|
||||
name: null,
|
||||
avatar: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
Mutation: {
|
||||
updateCurrentUser: (_, { id, email, isLoggedIn }, { cache }) => {
|
||||
updateCurrentUser: (_, { id, email, isLoggedIn, role }, { cache }) => {
|
||||
const data = {
|
||||
currentUser: {
|
||||
id,
|
||||
email,
|
||||
isLoggedIn,
|
||||
role,
|
||||
__typename: 'CurrentUser',
|
||||
},
|
||||
};
|
||||
|
||||
cache.writeData({ data });
|
||||
},
|
||||
updateCurrentActor: (_, { id, preferredUsername, avatar, name }, { cache }) => {
|
||||
const data = {
|
||||
currentActor: {
|
||||
id,
|
||||
preferredUsername,
|
||||
avatar,
|
||||
name,
|
||||
__typename: 'CurrentActor',
|
||||
},
|
||||
};
|
||||
|
||||
cache.writeData({ data });
|
||||
},
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<section>
|
||||
<h1 class="title">
|
||||
<translate>My identities</translate>
|
||||
{{ $t('My identities') }}
|
||||
</h1>
|
||||
|
||||
<ul class="identities">
|
||||
@ -24,7 +24,7 @@
|
||||
</ul>
|
||||
|
||||
<router-link :to="{ name: 'CreateIdentity' }" class="button create-identity is-primary" >
|
||||
<translate>Create a new identity</translate>
|
||||
{{ $t('Create a new identity') }}
|
||||
</router-link>
|
||||
</section>
|
||||
</template>
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { IDENTITIES, LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { IDENTITIES } from '@/graphql/actor';
|
||||
import { IPerson, Person } from '@/types/actor';
|
||||
|
||||
@Component({
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="editor" id="tiptab-editor" :data-actor-id="loggedPerson && loggedPerson.id">
|
||||
<div class="editor" id="tiptab-editor" :data-actor-id="currentActor && currentActor.id">
|
||||
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive, focused }">
|
||||
<div class="menubar bar-is-hidden" :class="{ 'is-focused': focused }">
|
||||
|
||||
@ -176,20 +176,20 @@ import { IActor, IPerson } from '@/types/actor';
|
||||
import Image from '@/components/Editor/Image';
|
||||
import { UPLOAD_PICTURE } from '@/graphql/upload';
|
||||
import { listenFileUpload } from '@/utils/upload';
|
||||
import { LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
||||
|
||||
@Component({
|
||||
components: { EditorContent, EditorMenuBar, EditorMenuBubble },
|
||||
apollo: {
|
||||
loggedPerson: {
|
||||
query: LOGGED_PERSON,
|
||||
currentActor: {
|
||||
query: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
},
|
||||
})
|
||||
export default class CreateEvent extends Vue {
|
||||
@Prop({ required: true }) value!: String;
|
||||
|
||||
loggedPerson!: IPerson;
|
||||
currentActor!: IPerson;
|
||||
|
||||
editor: Editor = null;
|
||||
|
||||
@ -438,7 +438,7 @@ export default class CreateEvent extends Vue {
|
||||
variables: {
|
||||
file: image,
|
||||
name: image.name,
|
||||
actorId: this.loggedPerson.id,
|
||||
actorId: this.currentActor.id,
|
||||
},
|
||||
});
|
||||
if (data.uploadPicture && data.uploadPicture.url) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-field label="Find an address">
|
||||
<b-field :label="$t('Find an address')">
|
||||
<b-autocomplete
|
||||
:data="data"
|
||||
v-model="queryText"
|
||||
placeholder="e.g. 10 Rue Jangot"
|
||||
:placeholder="$t('e.g. 10 Rue Jangot')"
|
||||
field="description"
|
||||
:loading="isFetching"
|
||||
@typing="getAsyncData"
|
||||
@ -18,12 +18,12 @@
|
||||
</p>
|
||||
</template>
|
||||
<template slot="empty">
|
||||
<span v-if="queryText.length < 5">Please type at least 5 caracters</span>
|
||||
<span v-else-if="isFetching">Searching…</span>
|
||||
<span v-if="queryText.length < 5">{{ $t('Please type at least 5 characters') }}</span>
|
||||
<span v-else-if="isFetching">{{ $t('Searching…') }}</span>
|
||||
<div v-else class="is-enabled">
|
||||
<span>No results for « {{ queryText }} »</span>
|
||||
<span>{{ $t('No results for "{queryText}"', { queryText }) }}</span>
|
||||
<p class="control" @click="addressModalActive = true">
|
||||
<button type="button" class="button is-primary">Add</button>
|
||||
<button type="button" class="button is-primary">{{ $t('Add') }}</button>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@ -32,37 +32,37 @@
|
||||
<b-modal :active.sync="addressModalActive" :width="640" has-modal-card scroll="keep">
|
||||
<div class="modal-card" style="width: auto">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">Login</p>
|
||||
<p class="modal-card-title">{{ $t('Add an address') }}</p>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<form>
|
||||
<b-field :label="$gettext('Name')">
|
||||
<b-field :label="$t('Name')">
|
||||
<b-input aria-required="true" required v-model="selected.description" />
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$gettext('Street')">
|
||||
<b-field :label="$t('Street')">
|
||||
<b-input v-model="selected.street" />
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$gettext('Postal Code')">
|
||||
<b-field :label="$t('Postal Code')">
|
||||
<b-input v-model="selected.postalCode" />
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$gettext('Locality')">
|
||||
<b-field :label="$t('Locality')">
|
||||
<b-input v-model="selected.locality" />
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$gettext('Region')">
|
||||
<b-field :label="$t('Region')">
|
||||
<b-input v-model="selected.region" />
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$gettext('Country')">
|
||||
<b-field :label="$t('Country')">
|
||||
<b-input v-model="selected.country" />
|
||||
</b-field>
|
||||
</form>
|
||||
</section>
|
||||
<footer class="modal-card-foot">
|
||||
<button class="button" type="button" @click="resetPopup()">Clear</button>
|
||||
<button class="button" type="button" @click="resetPopup()">{{ $t('Clear') }}</button>
|
||||
</footer>
|
||||
</div>
|
||||
</b-modal>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<b-field grouped horizontal :label="label">
|
||||
<b-datepicker expanded v-model="date" :placeholder="$gettext('Click to select')" icon="calendar"></b-datepicker>
|
||||
<b-datepicker expanded v-model="date" :placeholder="$t('Click to select')" icon="calendar"></b-datepicker>
|
||||
<b-input expanded type="time" required v-model="time" />
|
||||
</b-field>
|
||||
</template>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="tag-container" v-if="event.tags">
|
||||
<b-tag v-for="tag in event.tags.slice(0, 3)" :key="tag.slug" type="is-secondary">{{ tag.title }}</b-tag>
|
||||
</div>
|
||||
<img src="https://picsum.photos/g/400/225/?random">
|
||||
<img src="https://picsum.photos/g/400/225/?random" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class="content">
|
||||
@ -29,7 +29,7 @@
|
||||
<!-- <div v-else-if="event.participants.length === 1">-->
|
||||
<!-- <translate-->
|
||||
<!-- :translate-params="{name: event.participants[0].actor.preferredUsername}"-->
|
||||
<!-- >%{name} organizes this event</translate>-->
|
||||
<!-- >{name} organizes this event</translate>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-else>-->
|
||||
<!-- <span v-for="participant in event.participants" :key="participant.actor.uuid">-->
|
||||
@ -37,7 +37,7 @@
|
||||
<!-- <span v-if="participant.role === ParticipantRole.CREATOR">(organizer)</span>,-->
|
||||
<!-- <!– <translate-->
|
||||
<!-- :translate-params="{name: participant.actor.preferredUsername}"-->
|
||||
<!-- > %{name} is in,</translate>–>-->
|
||||
<!-- > {name} is in,</translate>–>-->
|
||||
<!-- </span>-->
|
||||
<!-- </div>-->
|
||||
</router-link>
|
||||
|
@ -1,16 +1,12 @@
|
||||
<template>
|
||||
<translate
|
||||
v-if="!endsOn"
|
||||
:translate-params="{date: formatDate(beginsOn), time: formatTime(beginsOn)}"
|
||||
>The %{ date } at %{ time }</translate>
|
||||
<translate
|
||||
v-else-if="isSameDay()"
|
||||
:translate-params="{date: formatDate(beginsOn), startTime: formatTime(beginsOn), endTime: formatTime(endsOn)}"
|
||||
>The %{ date } from %{ startTime } to %{ endTime }</translate>
|
||||
<translate
|
||||
v-else-if="endsOn"
|
||||
:translate-params="{startDate: formatDate(beginsOn), startTime: formatTime(beginsOn), endDate: formatDate(endsOn), endTime: formatTime(endsOn)}"
|
||||
>From the %{ startDate } at %{ startTime } to the %{ endDate } at %{ endTime }</translate>
|
||||
<span v-if="!endsOn">{{ beginsOn | formatDateTimeString }}</span>
|
||||
<span v-else-if="isSameDay()">
|
||||
{{ $t('The {date} from {startTime} to {endTime}', {date: formatDate(beginsOn), startTime: formatTime(beginsOn), endTime: formatTime(endsOn)}) }}
|
||||
</span>
|
||||
<span v-else-if="endsOn">
|
||||
{{ $t('From the {startDate} at {startTime} to the {endDate} at {endTime}',
|
||||
{startDate: formatDate(beginsOn), startTime: formatTime(beginsOn), endDate: formatDate(endsOn), endTime: formatTime(endsOn)}) }}
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
@ -21,11 +17,13 @@ export default class EventFullDate extends Vue {
|
||||
@Prop({ required: false }) endsOn!: string;
|
||||
|
||||
formatDate(value) {
|
||||
return value ? new Date(value).toLocaleString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) : null;
|
||||
if (!this.$options.filters) return;
|
||||
return this.$options.filters.formatDateString(value);
|
||||
}
|
||||
|
||||
formatTime(value) {
|
||||
return value ? new Date(value).toLocaleTimeString(undefined, { hour: 'numeric', minute: 'numeric' }) : null;
|
||||
if (!this.$options.filters) return;
|
||||
return this.$options.filters.formatTimeString(value);
|
||||
}
|
||||
|
||||
isSameDay() {
|
||||
|
86
js/src/components/Event/ParticipationModal.vue
Normal file
86
js/src/components/Event/ParticipationModal.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">Join event {{ event.title }}</p>
|
||||
</header>
|
||||
|
||||
<section class="modal-card-body is-flex">
|
||||
<div class="media">
|
||||
<div
|
||||
class="media-left">
|
||||
<b-icon
|
||||
icon="alert"
|
||||
type="is-warning"
|
||||
size="is-large"/>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p>Do you want to participate in {{ event.title }}?</p>
|
||||
|
||||
<b-field :label="$t('Identity')">
|
||||
<identity-picker v-model="identity"></identity-picker>
|
||||
</b-field>
|
||||
|
||||
<p v-if="!event.local">
|
||||
The event came from another instance. Your participation will be confirmed after we confirm it with the other instance.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="modal-card-foot">
|
||||
<button
|
||||
class="button"
|
||||
ref="cancelButton"
|
||||
@click="close">
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
class="button is-primary"
|
||||
ref="confirmButton"
|
||||
@click="confirm">
|
||||
Confirm my particpation
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { IEvent } from '@/types/event.model';
|
||||
import IdentityPicker from '@/views/Account/IdentityPicker.vue';
|
||||
import { IPerson } from '@/types/actor';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
IdentityPicker,
|
||||
},
|
||||
mounted() {
|
||||
this.$data.isActive = true;
|
||||
},
|
||||
})
|
||||
export default class ReportModal extends Vue {
|
||||
@Prop({ type: Function, default: () => {} }) onConfirm;
|
||||
@Prop({ type: Object }) event! : IEvent;
|
||||
@Prop({ type: Object }) defaultIdentity!: IPerson;
|
||||
|
||||
isActive: boolean = false;
|
||||
identity: IPerson = this.defaultIdentity;
|
||||
|
||||
confirm() {
|
||||
this.onConfirm(this.identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the Dialog.
|
||||
*/
|
||||
close() {
|
||||
this.isActive = false;
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.modal-card .modal-card-foot {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<b-field label="Enter some tags">
|
||||
<b-field :label="$t('Enter some tags')">
|
||||
<b-taginput
|
||||
v-model="tagsStrings"
|
||||
:data="filteredTags"
|
||||
@ -7,7 +7,7 @@
|
||||
:allow-new="true"
|
||||
:field="path"
|
||||
icon="label"
|
||||
placeholder="Add a tag"
|
||||
:placeholder="$t('Add a tag')"
|
||||
@typing="getFilteredTags"
|
||||
>
|
||||
</b-taginput>
|
||||
|
@ -1,18 +1,13 @@
|
||||
<template>
|
||||
<footer class="footer">
|
||||
<mobilizon-logo :invert="true" class="logo" />
|
||||
<img src="../assets/footer.png" :alt="$gettext('World map')" />
|
||||
<img src="../assets/footer.png" :alt="$t('World map')" />
|
||||
<ul>
|
||||
<li><router-link :to="{ name: 'About'}"><translate>About</translate></router-link></li>
|
||||
<li><router-link :to="{ name: 'Licence'}"><translate>License</translate></router-link></li>
|
||||
<li><router-link :to="{ name: 'Legal'}"><translate>Legal</translate></router-link></li>
|
||||
<li><a href="https://joinmobilizon.org">{{ $t('About') }}</a></li>
|
||||
<li><a href="https://framagit.org/framasoft/mobilizon/blob/master/LICENSE">{{ $t('License') }}</a></li>
|
||||
</ul>
|
||||
<div class="content has-text-centered">
|
||||
<span
|
||||
v-translate="{
|
||||
date: new Date().getFullYear(),
|
||||
}"
|
||||
>© The Mobilizon Contributors %{date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks</span>
|
||||
<span>{{ $t('© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks', { date: new Date().getFullYear()}) }}</span>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
@ -27,34 +27,54 @@
|
||||
<div class="navbar-item has-dropdown is-hoverable" v-if="currentUser.isLoggedIn">
|
||||
<a
|
||||
class="navbar-link"
|
||||
v-if="loggedPerson"
|
||||
v-if="currentActor"
|
||||
>
|
||||
<figure class="image is-24x24" v-if="loggedPerson.avatar">
|
||||
<img alt="avatarUrl" :src="loggedPerson.avatar.url">
|
||||
<figure class="image is-24x24" v-if="currentActor.avatar">
|
||||
<img alt="avatarUrl" :src="currentActor.avatar.url">
|
||||
</figure>
|
||||
<span>{{ loggedPerson.preferredUsername }}</span>
|
||||
<span>{{ currentActor.preferredUsername }}</span>
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown">
|
||||
<span class="navbar-item">
|
||||
<router-link :to="{ name: 'UpdateIdentity' }" v-translate>My account</router-link>
|
||||
</span>
|
||||
<div class="navbar-dropdown is-boxed">
|
||||
<div v-for="identity in identities" v-if="identities.length > 0">
|
||||
<a class="navbar-item" @click="setIdentity(identity)" :class="{ 'is-active': identity.id === currentActor.id }">
|
||||
<div class="media-left">
|
||||
<figure class="image is-24x24" v-if="identity.avatar">
|
||||
<img class="is-rounded" :src="identity.avatar.url">
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<span class="navbar-item">
|
||||
<router-link :to="{ name: ActorRouteName.CREATE_GROUP }" v-translate>Create group</router-link>
|
||||
</span>
|
||||
<div class="media-content">
|
||||
<h3>{{ identity.displayName() }}</h3>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a v-translate class="navbar-item" v-on:click="logout()">Log out</a>
|
||||
<hr class="navbar-divider">
|
||||
</div>
|
||||
|
||||
<a class="navbar-item">
|
||||
<router-link :to="{ name: 'UpdateIdentity' }">{{ $t('My account') }}</router-link>
|
||||
</a>
|
||||
|
||||
<a class="navbar-item">
|
||||
<router-link :to="{ name: ActorRouteName.CREATE_GROUP }">{{ $t('Create group') }}</router-link>
|
||||
</a>
|
||||
|
||||
<a class="navbar-item" v-if="currentUser.role === ICurrentUserRole.ADMINISTRATOR">
|
||||
<router-link :to="{ name: AdminRouteName.DASHBOARD }">{{ $t('Administration') }}</router-link>
|
||||
</a>
|
||||
|
||||
<a class="navbar-item" v-on:click="logout()">{{ $t('Log out') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-item" v-else>
|
||||
<div class="buttons">
|
||||
<router-link class="button is-primary" v-if="config && config.registrationsOpen" :to="{ name: 'Register' }">
|
||||
<strong v-translate>Sign up</strong>
|
||||
<strong>{{ $t('Sign up') }}</strong>
|
||||
</router-link>
|
||||
|
||||
<router-link class="button is-primary" :to="{ name: 'Login' }" v-translate>Log in</router-link>
|
||||
<router-link class="button is-primary" :to="{ name: 'Login' }">{{ $t('Log in') }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -66,21 +86,30 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue, Watch } from 'vue-property-decorator';
|
||||
import { CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { logout } from '@/utils/auth';
|
||||
import { LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { changeIdentity, logout } from '@/utils/auth';
|
||||
import { CURRENT_ACTOR_CLIENT, IDENTITIES, UPDATE_CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
||||
import { IPerson, Person } from '@/types/actor';
|
||||
import { CONFIG } from '@/graphql/config';
|
||||
import { IConfig } from '@/types/config.model';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import { ICurrentUser, ICurrentUserRole } from '@/types/current-user.model';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import SearchField from '@/components/SearchField.vue';
|
||||
import { ActorRouteName } from '@/router/actor';
|
||||
import { AdminRouteName } from '@/router/admin';
|
||||
import { RouteName } from '@/router';
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
currentUser: {
|
||||
query: CURRENT_USER_CLIENT,
|
||||
},
|
||||
currentActor: {
|
||||
query: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
identities: {
|
||||
query: IDENTITIES,
|
||||
update: ({ identities }) => identities.map(identity => new Person(identity)),
|
||||
},
|
||||
config: {
|
||||
query: CONFIG,
|
||||
},
|
||||
@ -95,31 +124,40 @@ export default class NavBar extends Vue {
|
||||
{ header: 'Coucou' },
|
||||
{ title: 'T\'as une notification', subtitle: 'Et elle est cool' },
|
||||
];
|
||||
loggedPerson: IPerson | null = null;
|
||||
currentActor!: IPerson;
|
||||
config!: IConfig;
|
||||
currentUser!: ICurrentUser;
|
||||
ICurrentUserRole = ICurrentUserRole;
|
||||
identities!: IPerson[];
|
||||
showNavbar: boolean = false;
|
||||
|
||||
ActorRouteName = ActorRouteName;
|
||||
AdminRouteName = AdminRouteName;
|
||||
|
||||
@Watch('currentUser')
|
||||
async onCurrentUserChanged() {
|
||||
// Refresh logged person object
|
||||
if (this.currentUser.isLoggedIn) {
|
||||
const result = await this.$apollo.query({
|
||||
query: LOGGED_PERSON,
|
||||
});
|
||||
|
||||
this.loggedPerson = result.data.loggedPerson;
|
||||
} else {
|
||||
this.loggedPerson = null;
|
||||
}
|
||||
}
|
||||
// @Watch('currentUser')
|
||||
// async onCurrentUserChanged() {
|
||||
// // Refresh logged person object
|
||||
// if (this.currentUser.isLoggedIn) {
|
||||
// const result = await this.$apollo.query({
|
||||
// query: CURRENT_ACTOR_CLIENT,
|
||||
// });
|
||||
// console.log(result);
|
||||
//
|
||||
// this.loggedPerson = result.data.currentActor;
|
||||
// } else {
|
||||
// this.loggedPerson = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
async logout() {
|
||||
await logout(this.$apollo.provider.defaultClient);
|
||||
|
||||
return this.$router.push({ path: '/' });
|
||||
if (this.$route.name === RouteName.HOME) return;
|
||||
return this.$router.push({ name: RouteName.HOME });
|
||||
}
|
||||
|
||||
async setIdentity(identity: IPerson) {
|
||||
return await changeIdentity(this.$apollo.provider.defaultClient, identity);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<b-upload @input="onFileChanged">
|
||||
<a class="button is-primary">
|
||||
<b-icon icon="upload"></b-icon>
|
||||
<span>Click to upload</span>
|
||||
<span>{{ $t('Click to upload') }}</span>
|
||||
</a>
|
||||
</b-upload>
|
||||
</div>
|
||||
@ -41,8 +41,12 @@ export default class PictureUpload extends Vue {
|
||||
|
||||
imageSrc: string | null = null;
|
||||
|
||||
mounted() {
|
||||
this.updatePreview(this.pictureFile);
|
||||
}
|
||||
|
||||
@Watch('pictureFile')
|
||||
onPictureFileChanged (val: File) {
|
||||
onPictureFileChanged(val: File) {
|
||||
this.updatePreview(val);
|
||||
}
|
||||
|
||||
|
45
js/src/components/Report/ReportCard.vue
Normal file
45
js/src/components/Report/ReportCard.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div class="card" v-if="report">
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48" v-if="report.reported.avatar">
|
||||
<img :src="report.reported.avatar.url" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-4">{{ report.reported.name }}</p>
|
||||
<p class="subtitle is-6">@{{ report.reported.preferredUsername }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content columns">
|
||||
<div class="column is-one-quarter box">Reported by <img v-if="report.reporter.avatar" class="image" :src="report.reporter.avatar.url" /> @{{ report.reporter.preferredUsername }}</div>
|
||||
<div class="column box" v-if="report.event">
|
||||
<img class="image" v-if="report.event.picture" :src="report.event.picture.url" />
|
||||
<span>{{ report.event.title }}</span>
|
||||
</div>
|
||||
<div class="column box" v-if="report.reportContent">{{ report.reportContent }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { IReport } from '@/types/report.model';
|
||||
import { EventRouteName } from '@/router/event';
|
||||
|
||||
@Component
|
||||
export default class ReportCard extends Vue {
|
||||
@Prop({ required: true }) report!: IReport;
|
||||
|
||||
EventRouteName = EventRouteName;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.content img.image {
|
||||
display: inline;
|
||||
height: 1.5em;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
</style>
|
97
js/src/components/Report/ReportModal.vue
Normal file
97
js/src/components/Report/ReportModal.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head" v-if="title">
|
||||
<p class="modal-card-title">{{ title }}</p>
|
||||
</header>
|
||||
|
||||
<section
|
||||
class="modal-card-body is-flex"
|
||||
:class="{ 'is-titleless': !title }">
|
||||
<div class="media">
|
||||
<div
|
||||
class="media-left">
|
||||
<b-icon
|
||||
icon="alert"
|
||||
type="is-warning"
|
||||
size="is-large"/>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p>The report will be sent to the moderators of your instance.
|
||||
You can explain why you report this content below.</p>
|
||||
|
||||
<div class="control">
|
||||
<b-input
|
||||
v-model="content"
|
||||
type="textarea"
|
||||
@keyup.enter="confirm"
|
||||
placeholder="Additional comments"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p v-if="outsideDomain">
|
||||
The content came from another server. Transfer an anonymous copy of the report ?
|
||||
</p>
|
||||
|
||||
<div class="control" v-if="outsideDomain">
|
||||
<b-switch v-model="forward">Transfer to {{ outsideDomain }}</b-switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="modal-card-foot">
|
||||
<button
|
||||
class="button"
|
||||
ref="cancelButton"
|
||||
@click="close">
|
||||
{{ cancelText }}
|
||||
</button>
|
||||
<button
|
||||
class="button is-primary"
|
||||
ref="confirmButton"
|
||||
@click="confirm">
|
||||
{{ confirmText }}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { removeElement } from 'buefy/src/utils/helpers';
|
||||
|
||||
@Component({
|
||||
mounted() {
|
||||
this.$data.isActive = true;
|
||||
},
|
||||
})
|
||||
export default class ReportModal extends Vue {
|
||||
@Prop({ type: Function, default: () => {} }) onConfirm;
|
||||
@Prop({ type: String }) title;
|
||||
@Prop({ type: String, default: '' }) outsideDomain;
|
||||
@Prop({ type: String, default: 'Cancel' }) cancelText;
|
||||
@Prop({ type: String, default: 'Send the report' }) confirmText;
|
||||
|
||||
isActive: boolean = false;
|
||||
content: string = '';
|
||||
forward: boolean = false;
|
||||
|
||||
confirm() {
|
||||
this.onConfirm(this.content, this.forward);
|
||||
this.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the Dialog.
|
||||
*/
|
||||
close() {
|
||||
this.isActive = false;
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.modal-card .modal-card-foot {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
@ -16,7 +16,7 @@ export default class SearchField extends Vue {
|
||||
|
||||
get defaultPlaceHolder(): string {
|
||||
// We can't use "this" inside @Prop's default value.
|
||||
return this.placeholder || this.$gettext('Search');
|
||||
return this.placeholder || this.$t('Search') as string;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -2,4 +2,5 @@ export const AUTH_ACCESS_TOKEN = 'auth-access-token';
|
||||
export const AUTH_REFRESH_TOKEN = 'auth-refresh-token';
|
||||
export const AUTH_USER_ID = 'auth-user-id';
|
||||
export const AUTH_USER_EMAIL = 'auth-user-email';
|
||||
export const AUTH_USER_ACTOR = 'auth-user-actor';
|
||||
export const AUTH_USER_ACTOR_ID = 'auth-user-actor-id';
|
||||
export const AUTH_USER_ROLE = 'auth-user-role';
|
||||
|
19
js/src/filters/datetime.ts
Normal file
19
js/src/filters/datetime.ts
Normal file
@ -0,0 +1,19 @@
|
||||
function parseDateTime(value: string): Date {
|
||||
return new Date(value);
|
||||
}
|
||||
|
||||
function formatDateString(value: string): string {
|
||||
return parseDateTime(value).toLocaleString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||
}
|
||||
|
||||
function formatTimeString(value: string): string {
|
||||
return parseDateTime(value).toLocaleTimeString(undefined, { hour: 'numeric', minute: 'numeric' });
|
||||
}
|
||||
|
||||
function formatDateTimeString(value: string): string {
|
||||
return parseDateTime(value).toLocaleTimeString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' });
|
||||
}
|
||||
|
||||
|
||||
|
||||
export { formatDateString, formatTimeString, formatDateTimeString };
|
9
js/src/filters/index.ts
Normal file
9
js/src/filters/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { formatDateString, formatTimeString, formatDateTimeString } from './datetime';
|
||||
|
||||
export default {
|
||||
install(vue) {
|
||||
vue.filter('formatDateString', formatDateString);
|
||||
vue.filter('formatTimeString', formatTimeString);
|
||||
vue.filter('formatDateTimeString', formatDateTimeString);
|
||||
},
|
||||
};
|
@ -40,6 +40,25 @@ query {
|
||||
}
|
||||
}`;
|
||||
|
||||
export const CURRENT_ACTOR_CLIENT = gql`
|
||||
query {
|
||||
currentActor @client {
|
||||
id,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_CURRENT_ACTOR_CLIENT = gql`
|
||||
mutation UpdateCurrentActor($id: String!, $avatar: String, $preferredUsername: String!, $name: String!) {
|
||||
updateCurrentActor(id: $id, avatar: $avatar, preferredUsername: $preferredUsername, name: $name) @client
|
||||
}
|
||||
`;
|
||||
|
||||
export const LOGGED_PERSON_WITH_GOING_TO_EVENTS = gql`
|
||||
query {
|
||||
loggedPerson {
|
||||
@ -177,7 +196,7 @@ query($name:String!) {
|
||||
|
||||
export const CREATE_GROUP = gql`
|
||||
mutation CreateGroup(
|
||||
$creatorActorId: Int!,
|
||||
$creatorActorId: ID!,
|
||||
$preferredUsername: String!,
|
||||
$name: String!,
|
||||
$summary: String,
|
||||
|
19
js/src/graphql/admin.ts
Normal file
19
js/src/graphql/admin.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const DASHBOARD = gql`
|
||||
query {
|
||||
dashboard {
|
||||
lastPublicEventPublished {
|
||||
title,
|
||||
picture {
|
||||
alt
|
||||
url
|
||||
},
|
||||
},
|
||||
numberOfUsers,
|
||||
numberOfEvents,
|
||||
numberOfComments,
|
||||
numberOfReports
|
||||
}
|
||||
}
|
||||
`;
|
@ -7,7 +7,8 @@ mutation Login($email: String!, $password: String!) {
|
||||
refreshToken,
|
||||
user {
|
||||
id,
|
||||
email
|
||||
email,
|
||||
role
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -12,6 +12,43 @@ const participantQuery = `
|
||||
}
|
||||
`;
|
||||
|
||||
const physicalAddressQuery = `
|
||||
description,
|
||||
floor,
|
||||
street,
|
||||
locality,
|
||||
postalCode,
|
||||
region,
|
||||
country,
|
||||
geom
|
||||
`;
|
||||
|
||||
const tagsQuery = `
|
||||
id,
|
||||
slug,
|
||||
title
|
||||
`;
|
||||
|
||||
const optionsQuery = `
|
||||
maximumAttendeeCapacity,
|
||||
remainingAttendeeCapacity,
|
||||
showRemainingAttendeeCapacity,
|
||||
offers {
|
||||
price,
|
||||
priceCurrency,
|
||||
url
|
||||
},
|
||||
participationConditions {
|
||||
title,
|
||||
content,
|
||||
url
|
||||
},
|
||||
attendees,
|
||||
program,
|
||||
commentModeration,
|
||||
showParticipationPrice
|
||||
`;
|
||||
|
||||
export const FETCH_EVENT = gql`
|
||||
query($uuid:UUID!) {
|
||||
event(uuid: $uuid) {
|
||||
@ -29,20 +66,14 @@ export const FETCH_EVENT = gql`
|
||||
picture {
|
||||
id
|
||||
url
|
||||
name
|
||||
},
|
||||
publishAt,
|
||||
category,
|
||||
# online_address,
|
||||
# phone_address,
|
||||
onlineAddress,
|
||||
phoneAddress,
|
||||
physicalAddress {
|
||||
description,
|
||||
floor,
|
||||
street,
|
||||
locality,
|
||||
postalCode,
|
||||
region,
|
||||
country,
|
||||
geom
|
||||
${physicalAddressQuery}
|
||||
}
|
||||
organizerActor {
|
||||
avatar {
|
||||
@ -64,10 +95,12 @@ export const FETCH_EVENT = gql`
|
||||
participants {
|
||||
${participantQuery}
|
||||
},
|
||||
participantStats {
|
||||
approved,
|
||||
unapproved
|
||||
},
|
||||
tags {
|
||||
id,
|
||||
slug,
|
||||
title
|
||||
${tagsQuery}
|
||||
},
|
||||
relatedEvents {
|
||||
uuid,
|
||||
@ -86,23 +119,7 @@ export const FETCH_EVENT = gql`
|
||||
}
|
||||
},
|
||||
options {
|
||||
maximumAttendeeCapacity,
|
||||
remainingAttendeeCapacity,
|
||||
showRemainingAttendeeCapacity,
|
||||
offers {
|
||||
price,
|
||||
priceCurrency,
|
||||
url
|
||||
},
|
||||
participationConditions {
|
||||
title,
|
||||
content,
|
||||
url
|
||||
},
|
||||
attendees,
|
||||
program,
|
||||
commentModeration,
|
||||
showParticipationPrice
|
||||
${optionsQuery}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,37 +176,62 @@ export const FETCH_EVENTS = gql`
|
||||
`;
|
||||
|
||||
export const CREATE_EVENT = gql`
|
||||
mutation CreateEvent(
|
||||
mutation createEvent(
|
||||
$organizerActorId: ID!,
|
||||
$title: String!,
|
||||
$description: String!,
|
||||
$organizerActorId: ID!,
|
||||
$category: String,
|
||||
$beginsOn: DateTime!,
|
||||
$endsOn: DateTime,
|
||||
$picture: PictureInput,
|
||||
$tags: [String],
|
||||
$options: EventOptionsInput,
|
||||
$physicalAddress: AddressInput,
|
||||
$status: EventStatus,
|
||||
$visibility: EventVisibility
|
||||