@@ -71,18 +73,10 @@ export default class App extends Vue {
/* Buefy imports */
@import "~buefy/src/scss/buefy";
-.router-enter-active,
-.router-leave-active {
- transition-property: opacity;
- transition-duration: 0.25s;
+.fade-enter-active, .fade-leave-active {
+ transition: opacity .5s;
}
-
-.router-enter-active {
- transition-delay: 0.25s;
-}
-
-.router-enter,
-.router-leave-active {
+.fade-enter, .fade-leave-to {
opacity: 0;
}
diff --git a/js/src/components/NavBar.vue b/js/src/components/NavBar.vue
index 7b77a5fce..6632a990d 100644
--- a/js/src/components/NavBar.vue
+++ b/js/src/components/NavBar.vue
@@ -15,7 +15,7 @@
-
+
@@ -82,6 +82,7 @@ import { ICurrentUser, ICurrentUserRole } from '@/types/current-user.model';
import Logo from '@/components/Logo.vue';
import SearchField from '@/components/SearchField.vue';
import { RouteName } from '@/router';
+import { GraphQLError } from 'graphql';
@Component({
apollo: {
@@ -97,6 +98,7 @@ import { RouteName } from '@/router';
skip() {
return this.currentUser.isLoggedIn === false;
},
+ error({ graphQLErrors }) { this.handleErrors(graphQLErrors); },
},
config: {
query: CONFIG,
@@ -135,6 +137,12 @@ export default class NavBar extends Vue {
}
}
+ async handleErrors(errors: GraphQLError) {
+ if (errors[0].message === 'You need to be logged-in to view your list of identities') {
+ await this.logout();
+ }
+ }
+
async logout() {
await logout(this.$apollo.provider.defaultClient);
this.$buefy.notification.open({
diff --git a/js/src/graphql/user.ts b/js/src/graphql/user.ts
index ae7ee2629..6a3e82081 100644
--- a/js/src/graphql/user.ts
+++ b/js/src/graphql/user.ts
@@ -1,8 +1,8 @@
import gql from 'graphql-tag';
export const CREATE_USER = gql`
-mutation CreateUser($email: String!, $password: String!) {
- createUser(email: $email, password: $password) {
+mutation CreateUser($email: String!, $password: String!, $locale: String) {
+ createUser(email: $email, password: $password, locale: $locale) {
email,
confirmationSentAt
}
diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index 6357caac5..14c63e478 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -173,7 +173,7 @@
"Past events": "Passed events",
"Pick an identity": "Pick an identity",
"Please be nice to each other": "Please be nice to each other",
- "Please check you spam folder if you didn't receive the email.": "Please check you spam folder if you didn't receive the email.",
+ "Please check your spam folder if you didn't receive the email.": "Please check your spam folder if you didn't receive the email.",
"Please contact this instance's Mobilizon admin if you think this is a mistake.": "Please contact this instance's Mobilizon admin if you think this is a mistake.",
"Please make sure the address is correct and that the page hasn't been moved.": "Please make sure the address is correct and that the page hasn't been moved.",
"Please read the full rules": "Please read the full rules",
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index 1b87577d2..e8d9e5987 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -159,7 +159,7 @@
"Past events": "Événements passés",
"Pick an identity": "Choisissez une identité",
"Please be nice to each other": "Soyez sympas entre vous",
- "Please check you spam folder if you didn't receive the email.": "Merci de vérifier votre dossier des indésirables si vous n'avez pas reçu l'email.",
+ "Please check your spam folder if you didn't receive the email.": "Merci de vérifier votre dossier des indésirables si vous n'avez pas reçu l'email.",
"Please contact this instance's Mobilizon admin if you think this is a mistake.": "Veuillez contacter l'administrateur de cette instance Mobilizon si vous pensez qu’il s’agit d’une erreur.",
"Please make sure the address is correct and that the page hasn't been moved.": "Assurez‐vous que l’adresse est correcte et que la page n’a pas été déplacée.",
"Please read the full rules": "Merci de lire les règles complètes",
diff --git a/js/src/i18n/oc.json b/js/src/i18n/oc.json
index 82f28745f..d80296929 100644
--- a/js/src/i18n/oc.json
+++ b/js/src/i18n/oc.json
@@ -224,7 +224,7 @@
"The event organizer has chosen to approve manually the participations to this event. You will receive a notification when your participation has been approved": "L’organizator de l’eveniment causèt d’aprovar manualament las participacions d’aqueste eveniment. Recebretz una notificacion quand serà aprovada",
"The event came from another instance. Your participation will be confirmed after we confirm it with the other instance.": "L’eveniment ven d’una autra instància. Vòstra participacion serà confirmada aprèp qu’ajam recebut la confirmacion de l’autra instància.",
"Please contact this instance's Mobilizon admin if you think this is a mistake.": "Volgatz contactar l’administrator d’aquesta instància Mobilizon se pensatz qu’es una error.",
- "Please check you spam folder if you didn't receive the email.": "Mercés de verificar vòstre dorsièr de messatges indesirables s’avètz pas recebut lo corrièl.",
+ "Please check your spam folder if you didn't receive the email.": "Mercés de verificar vòstre dorsièr de messatges indesirables s’avètz pas recebut lo corrièl.",
"If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "S’aquesta identitat es l’unica que pòt administrar unes grops, vos cal los suprimir d’en primièr per dire de poder suprimir aquesta identitat.",
"The content came from another server. Transfer an anonymous copy of the report?": "Lo contengut ven d’una autra instància. Transferir una còpia anonima del senhalament ?",
"Please make sure the address is correct and that the page hasn't been moved.": "Asseguratz-vos que l’adreça es corrècta e que la pagina es pas estada desplaçada.",
diff --git a/js/src/utils/image.ts b/js/src/utils/image.ts
index 8eeba866b..372eab73e 100644
--- a/js/src/utils/image.ts
+++ b/js/src/utils/image.ts
@@ -22,3 +22,17 @@ export function buildFileVariable(file: File | null, name: string, alt?: stri
},
};
}
+
+export function readFileAsync(file: File): Promise {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+
+ reader.onload = () => {
+ resolve(reader.result);
+ };
+
+ reader.onerror = reject;
+
+ reader.readAsBinaryString(file);
+ });
+}
diff --git a/js/src/views/Account/children/EditIdentity.vue b/js/src/views/Account/children/EditIdentity.vue
index 93bd14621..7233b92ea 100644
--- a/js/src/views/Account/children/EditIdentity.vue
+++ b/js/src/views/Account/children/EditIdentity.vue
@@ -94,7 +94,7 @@ import PictureUpload from '@/components/PictureUpload.vue';
import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint';
import { Dialog } from 'buefy/dist/components/dialog';
import { RouteName } from '@/router';
-import { buildFileFromIPicture, buildFileVariable } from '@/utils/image';
+import { buildFileFromIPicture, buildFileVariable, readFileAsync } from '@/utils/image';
import { changeIdentity } from '@/utils/auth';
@Component({
@@ -198,9 +198,11 @@ export default class EditIdentity extends Vue {
async updateIdentity() {
try {
+ const variables = await this.buildVariables();
+
await this.$apollo.mutate({
mutation: UPDATE_PERSON,
- variables: this.buildVariables(),
+ variables,
update: (store, { data: { updatePerson } }) => {
const data = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES });
@@ -225,9 +227,11 @@ export default class EditIdentity extends Vue {
async createIdentity() {
try {
+ const variables = await this.buildVariables();
+
await this.$apollo.mutate({
mutation: CREATE_PERSON,
- variables: this.buildVariables(),
+ variables,
update: (store, { data: { createPerson } }) => {
const data = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES });
@@ -305,10 +309,21 @@ export default class EditIdentity extends Vue {
.replace(/[^a-z0-9._]/g, '');
}
- private buildVariables() {
+ private async buildVariables() {
const avatarObj = buildFileVariable(this.avatarFile, 'avatar', `${this.identity.preferredUsername}'s avatar`);
-
- return Object.assign({}, this.identity, avatarObj);
+ const res = Object.assign({}, this.identity, avatarObj);
+ /**
+ * If the avatar didn't change, no need to try reuploading it
+ */
+ if (this.identity.avatar) {
+ const oldAvatarFile = await buildFileFromIPicture(this.identity.avatar) as File;
+ const oldAvatarFileContent = await readFileAsync(oldAvatarFile);
+ const newAvatarFileContent = await readFileAsync(this.avatarFile as File);
+ if (oldAvatarFileContent === newAvatarFileContent) {
+ res.avatar = null;
+ }
+ }
+ return res;
}
private async redirectIfNoIdentitySelected (identityParam?: string) {
diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue
index c59f134f0..a6ed34a4b 100644
--- a/js/src/views/Event/Event.vue
+++ b/js/src/views/Event/Event.vue
@@ -1,204 +1,204 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ event.title }}
+
+
+
+ {{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }}
+
+
+ {{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
+
+
+
+
+
-
{{ event.title }}
-
-
- {{ $tc('One person is going', event.participantStats.approved, {approved: event.participantStats.approved}) }}
-
-
- {{ $tc('You and one other person are going to this event', event.participantStats.approved - 1, {approved: event.participantStats.approved - 1}) }}
-
-
+