Replace Vuetify with Bulma
Signed-off-by: Thomas Citharel <tcit@tcit.fr> Remove vuetify and add Bulma Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -1,213 +0,0 @@
|
||||
<template>
|
||||
<v-layout row>
|
||||
<v-flex xs12 sm6 offset-sm3>
|
||||
<v-progress-circular v-if="$apollo.loading" indeterminate color="primary"></v-progress-circular>
|
||||
<v-card v-if="actor">
|
||||
<v-img :src="actor.banner || 'https://picsum.photos/400/'" height="300px">
|
||||
<v-layout column class="media">
|
||||
<v-card-title>
|
||||
<v-btn icon @click="$router.go(-1)">
|
||||
<v-icon>chevron_left</v-icon>
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<!-- <v-btn icon class="mr-3" v-if="actor.id === actor.id">
|
||||
<v-icon>edit</v-icon>
|
||||
</v-btn> -->
|
||||
<v-menu bottom left>
|
||||
<v-btn icon slot="activator">
|
||||
<v-icon>more_vert</v-icon>
|
||||
</v-btn>
|
||||
<v-list>
|
||||
<!-- <v-list-tile @click="logoutUser()" v-if="actor.id === actor.id">
|
||||
<v-list-tile-title>User logout</v-list-tile-title>
|
||||
</v-list-tile>
|
||||
<v-list-tile @click="deleteAccount()" v-if="actor.id === actor.id">
|
||||
<v-list-tile-title>Delete</v-list-tile-title>
|
||||
</v-list-tile> -->
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-card-title>
|
||||
<v-spacer></v-spacer>
|
||||
<div class="text-xs-center">
|
||||
<v-avatar size="125px">
|
||||
<img v-if="!actor.avatarUrl"
|
||||
class="img-circle elevation-7 mb-1"
|
||||
src="https://picsum.photos/125/125/"
|
||||
>
|
||||
<img v-else
|
||||
class="img-circle elevation-7 mb-1"
|
||||
:src="actor.avatarUrl"
|
||||
>
|
||||
</v-avatar>
|
||||
</div>
|
||||
<v-container fluid grid-list-lg>
|
||||
<v-layout row>
|
||||
<v-flex xs7>
|
||||
<div class="headline">{{ actor.name }}</div>
|
||||
<div><span class="subheading">@{{ actor.preferredUsername }}<span v-if="actor.domain">@{{ actor.domain }}</span></span>
|
||||
</div>
|
||||
<v-card-text v-if="actor.description" v-html="actor.description"></v-card-text>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-layout>
|
||||
</v-img>
|
||||
<v-list three-line>
|
||||
<v-list-tile>
|
||||
<v-list-tile-action>
|
||||
<v-icon color="indigo">phone</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>(323) 555-6789</v-list-tile-title>
|
||||
<v-list-tile-sub-title>Work</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
<v-list-tile-action>
|
||||
<v-icon dark>chat</v-icon>
|
||||
</v-list-tile-action>
|
||||
</v-list-tile>
|
||||
<v-divider inset></v-divider>
|
||||
<v-list-tile>
|
||||
<v-list-tile-action>
|
||||
<v-icon color="indigo">mail</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>ali_connors@example.com</v-list-tile-title>
|
||||
<v-list-tile-sub-title>Work</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
<v-divider inset></v-divider>
|
||||
<v-list-tile>
|
||||
<v-list-tile-action>
|
||||
<v-icon color="indigo">location_on</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>1400 Main Street</v-list-tile-title>
|
||||
<v-list-tile-sub-title>Orlando, FL 79938</v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-container fluid grid-list-md v-if="actor.participatingEvents && actor.participatingEvents.length > 0">
|
||||
<v-subheader>Participated at</v-subheader>
|
||||
<v-layout row wrap>
|
||||
<v-flex v-for="event in actor.participatingEvents" :key="event.id">
|
||||
<v-card>
|
||||
<v-img
|
||||
class="black--text"
|
||||
height="200px"
|
||||
src="https://picsum.photos/400/200/"
|
||||
>
|
||||
<v-container fill-height fluid>
|
||||
<v-layout fill-height>
|
||||
<v-flex xs12 align-end flexbox>
|
||||
<span class="headline">{{ event.title }}</span>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-img>
|
||||
<v-card-title>
|
||||
<div>
|
||||
<span class="grey--text">{{ event.startDate | formatDate }} à {{ event.location }}</span><br>
|
||||
<p>{{ event.description }}</p>
|
||||
<p v-if="event.organizer">Organisé par
|
||||
<router-link :to="{name: 'Account', params: {'id': event.organizer.id}}">{{ event.organizer.username }}</router-link>
|
||||
</p>
|
||||
</div>
|
||||
</v-card-title>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon>
|
||||
<v-icon>favorite</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>bookmark</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>share</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
<v-container fluid grid-list-md v-if="actor.organizedEvents && actor.organizedEvents.length > 0">
|
||||
<v-subheader>Organized events</v-subheader>
|
||||
<v-layout row wrap>
|
||||
<v-flex v-for="event in actor.organizedEvents" :key="event.id" md6>
|
||||
<v-card>
|
||||
<v-img
|
||||
height="200px"
|
||||
src="https://picsum.photos/400/200/"
|
||||
/>
|
||||
<v-card-title primary-title>
|
||||
<div>
|
||||
<router-link :to="{name: 'Event', params: {uuid: event.uuid}}">
|
||||
<div class="headline">{{ event.title }}</div>
|
||||
</router-link>
|
||||
<span class="grey--text" v-html="nl2br(event.description)"></span>
|
||||
</div>
|
||||
</v-card-title>
|
||||
|
||||
<!-- <v-card-title>
|
||||
<div>
|
||||
<span class="grey--text" v-if="event.addressType === 'physical'">{{ event.startDate }} à {{ event.location }}</span><br>
|
||||
<p v-if="event.organizer">Organisé par <router-link :to="{name: 'Account', params: {'id': event.organizer.id}}">{{ event.organizer.username }}</router-link></p>
|
||||
</div>
|
||||
</v-card-title> -->
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon>
|
||||
<v-icon>favorite</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>bookmark</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon>
|
||||
<v-icon>share</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { FETCH_ACTOR } from '@/graphql/actor';
|
||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
actor: {
|
||||
query: FETCH_ACTOR,
|
||||
variables() {
|
||||
return {
|
||||
name: this.$route.params.name,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
export default class Account extends Vue {
|
||||
@Prop({ type: String, required: true }) name!: string;
|
||||
|
||||
actor = null;
|
||||
|
||||
// call again the method if the route changes
|
||||
@Watch('$route')
|
||||
onRouteChange() {
|
||||
// this.fetchData()
|
||||
}
|
||||
|
||||
logoutUser() {
|
||||
// TODO : implement logout
|
||||
this.$router.push({ name: 'Home' });
|
||||
}
|
||||
|
||||
nl2br(text) {
|
||||
return text.replace(/(?:\r\n|\r|\n)/g, '<br>');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,133 +0,0 @@
|
||||
<template>
|
||||
<v-layout row>
|
||||
<v-flex xs12 sm6 offset-sm3>
|
||||
<v-progress-circular v-if="loading" indeterminate color="primary"></v-progress-circular>
|
||||
<v-card v-if="!loading">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Identities</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-list two-line>
|
||||
<v-list-tile
|
||||
v-for="actor in actors"
|
||||
:key="actor.id"
|
||||
avatar
|
||||
@click="$router.push({ name: 'Account', params: { name: actor.username } })"
|
||||
>
|
||||
<v-list-tile-action>
|
||||
<v-icon v-if="defaultActor === actor.username" color="pink">star</v-icon>
|
||||
</v-list-tile-action>
|
||||
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title v-text="actor.username"></v-list-tile-title>
|
||||
<v-list-tile-sub-title v-if="actor.display_name" v-text="actor.display_name"></v-list-tile-sub-title>
|
||||
</v-list-tile-content>
|
||||
|
||||
<v-list-tile-avatar>
|
||||
<img :src="actor.avatar">
|
||||
</v-list-tile-avatar>
|
||||
</v-list-tile>
|
||||
</v-list>
|
||||
<v-divider v-if="showForm"></v-divider>
|
||||
<v-form v-if="showForm">
|
||||
<v-text-field
|
||||
label="Username"
|
||||
required
|
||||
type="text"
|
||||
v-model="newActor.preferred_username"
|
||||
:rules="[rules.required]"
|
||||
:error="this.state.username.status"
|
||||
:error-messages="this.state.username.msg"
|
||||
:suffix="this.host()"
|
||||
hint="You will be able to create more identities once registered"
|
||||
persistent-hint
|
||||
>
|
||||
</v-text-field>
|
||||
<v-textarea
|
||||
name="input-7-1"
|
||||
label="Profile description"
|
||||
hint="Will be displayed publicly on your profile"
|
||||
></v-textarea>
|
||||
</v-form>
|
||||
<v-btn
|
||||
color="pink"
|
||||
dark
|
||||
absolute
|
||||
bottom
|
||||
right
|
||||
fab
|
||||
@click="toggleForm()"
|
||||
>
|
||||
<v-icon>{{ showForm ? 'check' : 'add' }}</v-icon>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
@Component
|
||||
export default class Identities extends Vue {
|
||||
actors = [];
|
||||
newActor = {
|
||||
preferred_username: '',
|
||||
summary: '',
|
||||
};
|
||||
loading = true;
|
||||
showForm = false;
|
||||
rules = {
|
||||
required: value => !!value || 'Required.',
|
||||
};
|
||||
state = {
|
||||
username: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
};
|
||||
|
||||
created() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
fetchData() {
|
||||
// Implements eventFetch
|
||||
// eventFetch('/user', this.$store)
|
||||
// .then(response => response.json())
|
||||
// .then((response) => {
|
||||
// this.actors = response.data.actors;
|
||||
// this.loading = false;
|
||||
// });
|
||||
}
|
||||
|
||||
sendData() {
|
||||
this.loading = true;
|
||||
this.showForm = false;
|
||||
|
||||
// Implements eventFetch
|
||||
// eventFetch('/actors', this.$store, {
|
||||
// method: 'POST',
|
||||
// body: JSON.stringify({ actor: this.newActor }),
|
||||
// })
|
||||
// .then(response => response.json())
|
||||
// .then((response) => {
|
||||
// this.actors.push(response.data);
|
||||
// this.loading = false;
|
||||
// });
|
||||
}
|
||||
|
||||
toggleForm() {
|
||||
if (this.showForm === true) {
|
||||
this.sendData();
|
||||
} else {
|
||||
this.showForm = true;
|
||||
}
|
||||
}
|
||||
|
||||
host() {
|
||||
return `@${window.location.host}`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,151 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md4>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Login</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip bottom>
|
||||
<v-btn
|
||||
slot="activator"
|
||||
:to="{ name: 'Register', params: { email: this.credentials.email, password: this.credentials.password } }"
|
||||
>
|
||||
<!-- <v-icon large>login</v-icon> -->
|
||||
<span>Register</span>
|
||||
</v-btn>
|
||||
<span>Register</span>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<div class="text-xs-center">
|
||||
<v-avatar size="80px">
|
||||
<transition name="avatar">
|
||||
<component :is="validEmail()" v-bind="{email: credentials.email}"></component>
|
||||
<!-- <v-gravatar :email="credentials.email" default-img="mp" v-if="validEmail()"/>
|
||||
<avatar v-else></avatar> -->
|
||||
</transition>
|
||||
</v-avatar>
|
||||
</div>
|
||||
<v-form @submit="loginAction" v-if="!validationSent">
|
||||
<v-text-field
|
||||
label="Email"
|
||||
required
|
||||
type="text"
|
||||
v-model="credentials.email"
|
||||
:rules="[rules.required, rules.email]"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
label="password"
|
||||
required
|
||||
type="password"
|
||||
v-model="credentials.password"
|
||||
:rules="[rules.required]"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn @click="loginAction" color="blue">Login</v-btn>
|
||||
<router-link :to="{ name: 'SendPasswordReset', params: { email: credentials.email } }">Password forgotten ?</router-link>
|
||||
</v-form>
|
||||
<div v-else>
|
||||
<h2>{{ $t('registration.form.validation_sent', { email: credentials.email }) }}</h2>
|
||||
<b-alert show variant="info">{{ $t('registration.form.validation_sent_info') }}</b-alert>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import Gravatar from 'vue-gravatar';
|
||||
import RegisterAvatar from './RegisterAvatar.vue';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { LOGIN } from '@/graphql/auth';
|
||||
import { validateEmailField, validateRequiredField } from '@/utils/validators';
|
||||
import { saveUserData } from '@/utils/auth';
|
||||
import { ILogin } from '@/types/login.model'
|
||||
import { UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user'
|
||||
import { onLogin } from '@/vue-apollo'
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
'v-gravatar': Gravatar,
|
||||
avatar: RegisterAvatar,
|
||||
},
|
||||
})
|
||||
export default class Login extends Vue {
|
||||
@Prop({ type: String, required: false, default: '' }) email!: string;
|
||||
@Prop({ type: String, required: false, default: '' }) password!: string;
|
||||
|
||||
credentials = {
|
||||
email: '',
|
||||
password: '',
|
||||
};
|
||||
validationSent = false;
|
||||
error = {
|
||||
show: false,
|
||||
text: '',
|
||||
timeout: 3000,
|
||||
field: {
|
||||
email: false,
|
||||
password: false,
|
||||
},
|
||||
};
|
||||
rules = {
|
||||
required: validateRequiredField,
|
||||
email: validateEmailField
|
||||
};
|
||||
user: any;
|
||||
|
||||
beforeCreate() {
|
||||
if (this.user) {
|
||||
this.$router.push('/');
|
||||
}
|
||||
}
|
||||
|
||||
mounted() {
|
||||
this.credentials.email = this.email;
|
||||
this.credentials.password = this.password;
|
||||
}
|
||||
|
||||
async loginAction(e: Event) {
|
||||
e.preventDefault();
|
||||
this.error.show = false;
|
||||
|
||||
try {
|
||||
const result = await this.$apollo.mutate<{ login: ILogin }>({
|
||||
mutation: LOGIN,
|
||||
variables: {
|
||||
email: this.credentials.email,
|
||||
password: this.credentials.password,
|
||||
},
|
||||
});
|
||||
|
||||
saveUserData(result.data.login);
|
||||
|
||||
await this.$apollo.mutate({
|
||||
mutation: UPDATE_CURRENT_USER_CLIENT,
|
||||
variables: {
|
||||
id: result.data.login.user.id,
|
||||
email: this.credentials.email,
|
||||
}
|
||||
});
|
||||
|
||||
onLogin(this.$apollo);
|
||||
|
||||
this.$router.push({ name: 'Home' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.error.show = true;
|
||||
this.error.text = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
validEmail() {
|
||||
return this.rules.email(this.credentials.email) === true ? 'v-gravatar' : 'avatar';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,123 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md4>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Password Reset</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-alert type="error" :value="state.token.status === false">{{ state.token.msg }}</v-alert>
|
||||
<v-form @submit="resetAction">
|
||||
<v-text-field
|
||||
label="Password"
|
||||
type="password"
|
||||
v-model="credentials.password"
|
||||
required
|
||||
:error="state.password.status"
|
||||
:rules="[rules.required, rules.password_length]"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
label="Password (confirmation)"
|
||||
type="password"
|
||||
v-model="credentials.password_confirmation"
|
||||
required
|
||||
:rules="[rules.required, rules.password_length, rules.password_equal]"
|
||||
:error="state.password_confirmation.status"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn type="submit" :disabled="!samePasswords" color="blue">Reset my password</v-btn>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { validateRequiredField } from '@/utils/validators';
|
||||
import { RESET_PASSWORD } from '@/graphql/auth';
|
||||
import { saveUserData } from '@/utils/auth';
|
||||
import { ILogin } from '@/types/login.model'
|
||||
|
||||
@Component
|
||||
export default class PasswordReset extends Vue {
|
||||
@Prop({ type: String, required: true }) token!: string;
|
||||
|
||||
credentials = {
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
};
|
||||
error = {
|
||||
show: false,
|
||||
};
|
||||
state = {
|
||||
token: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
password: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
password_confirmation: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
};
|
||||
rules = {
|
||||
password_length: value => value.length > 6 || 'Password must be at least 6 characters long',
|
||||
required: validateRequiredField,
|
||||
password_equal: value => value === this.credentials.password || 'Passwords must be the same',
|
||||
};
|
||||
|
||||
get samePasswords() {
|
||||
return this.rules.password_length(this.credentials.password) === true &&
|
||||
this.credentials.password === this.credentials.password_confirmation;
|
||||
}
|
||||
|
||||
async resetAction(e) {
|
||||
this.resetState();
|
||||
this.error.show = false;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
const result = await this.$apollo.mutate<{ resetPassword: ILogin}>({
|
||||
mutation: RESET_PASSWORD,
|
||||
variables: {
|
||||
password: this.credentials.password,
|
||||
token: this.token,
|
||||
},
|
||||
});
|
||||
|
||||
saveUserData(result.data.resetPassword);
|
||||
this.$router.push({ name: 'Home' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.error.show = true;
|
||||
}
|
||||
}
|
||||
|
||||
resetState() {
|
||||
this.state = {
|
||||
token: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
password_confirmation: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
password: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,185 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md4>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Register</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip bottom>
|
||||
<v-btn
|
||||
slot="activator"
|
||||
:to="{ name: 'Login', params: { email, password } }"
|
||||
>
|
||||
<!-- <v-icon large>login</v-icon> -->
|
||||
<span>Login</span>
|
||||
</v-btn>
|
||||
<span>Login</span>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<div class="text-xs-center">
|
||||
<v-avatar size="80px">
|
||||
<transition name="avatar">
|
||||
<component :is="validEmail()" v-bind="{email}"></component>
|
||||
<!-- <v-gravatar :email="credentials.email" default-img="mp" v-if="validEmail()"/>
|
||||
<avatar v-else></avatar> -->
|
||||
</transition>
|
||||
</v-avatar>
|
||||
</div>
|
||||
<v-form @submit="submit()" v-if="!validationSent">
|
||||
<v-text-field
|
||||
label="Username"
|
||||
required
|
||||
type="text"
|
||||
v-model="username"
|
||||
:rules="[rules.required]"
|
||||
:error="state.username.status"
|
||||
:error-messages="state.username.msg"
|
||||
:suffix="host()"
|
||||
hint="You will be able to create more identities once registered"
|
||||
persistent-hint
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
label="Email"
|
||||
required
|
||||
type="email"
|
||||
ref="email"
|
||||
v-model="email"
|
||||
:rules="[rules.required, rules.email]"
|
||||
:error="state.email.status"
|
||||
:error-messages="state.email.msg"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field
|
||||
label="Password"
|
||||
required
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
v-model="password"
|
||||
:rules="[rules.required, rules.password_length]"
|
||||
:error="state.password.status"
|
||||
:error-messages="state.password.msg"
|
||||
:append-icon="showPassword ? 'visibility_off' : 'visibility'"
|
||||
@click:append="showPassword = !showPassword"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn @click="submit()" color="primary">Register</v-btn>
|
||||
<router-link :to="{ name: 'ResendConfirmation', params: { email }}">Didn't receive the instructions ?</router-link>
|
||||
</v-form>
|
||||
<div v-if="validationSent">
|
||||
<h2>
|
||||
<translate>A validation email was sent to %{email}</translate>
|
||||
</h2>
|
||||
<v-alert :value="true" type="info">
|
||||
<translate>Before you can login, you need to click on the link inside it to validate your account</translate>
|
||||
</v-alert>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Gravatar from 'vue-gravatar';
|
||||
import RegisterAvatar from './RegisterAvatar.vue';
|
||||
import { CREATE_USER } from '@/graphql/user';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
'v-gravatar': Gravatar,
|
||||
avatar: RegisterAvatar,
|
||||
},
|
||||
})
|
||||
export default class Register extends Vue {
|
||||
@Prop({ type: String, required: false, default: '' }) default_email!: string;
|
||||
@Prop({ type: String, required: false, default: '' }) default_password!: string;
|
||||
|
||||
username = '';
|
||||
email = this.default_email;
|
||||
password = this.default_password;
|
||||
error = {
|
||||
show: false,
|
||||
};
|
||||
showPassword = false;
|
||||
validationSent = false;
|
||||
state = {
|
||||
email: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
username: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
password: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
};
|
||||
rules = {
|
||||
password_length: value => value.length > 6 || 'Password must be at least 6 characters long',
|
||||
required: value => !!value || 'Required.',
|
||||
email: (value: string) => value.includes('@') || 'Invalid e-mail.',
|
||||
};
|
||||
|
||||
resetState() {
|
||||
this.state = {
|
||||
email: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
username: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
password: {
|
||||
status: false,
|
||||
msg: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
host() {
|
||||
return `@${window.location.host}`;
|
||||
}
|
||||
|
||||
validEmail() {
|
||||
return this.rules.email(this.email) === true ? 'v-gravatar' : 'avatar';
|
||||
}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: CREATE_USER,
|
||||
variables: {
|
||||
email: this.email,
|
||||
password: this.password,
|
||||
username: this.username,
|
||||
},
|
||||
});
|
||||
|
||||
this.validationSent = true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.avatar-enter-active {
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
.avatar-enter, .avatar-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.avatar-leave {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +0,0 @@
|
||||
<template>
|
||||
<img class="img-circle elevation-7 mb-1" src="@/assets/profile.svg">
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
@Component
|
||||
export default class RegisterAvatar extends Vue {
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md4>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Resend Instructions</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-form @submit="resendConfirmationAction" v-if="!validationSent">
|
||||
<v-text-field
|
||||
label="Email"
|
||||
type="email"
|
||||
v-model="credentials.email"
|
||||
required
|
||||
:state="state.email.status"
|
||||
:rules="[rules.required, rules.email]"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn type="submit" color="blue">Send instructions again</v-btn>
|
||||
</v-form>
|
||||
<div v-else>
|
||||
<h2>Validation email sent to {{ credentials.email }}</h2>
|
||||
<v-alert :value="true" type="info">Please check you spam folder if you didn't receive the email.</v-alert>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { validateEmailField, validateRequiredField } from '@/utils/validators';
|
||||
import { RESEND_CONFIRMATION_EMAIL } from '@/graphql/auth';
|
||||
|
||||
@Component
|
||||
export default class ResendConfirmation extends Vue {
|
||||
@Prop({ type: String, required: false, default: '' }) email!: string;
|
||||
|
||||
credentials = {
|
||||
email: '',
|
||||
};
|
||||
validationSent = false;
|
||||
error = false;
|
||||
state = {
|
||||
email: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
};
|
||||
rules = {
|
||||
required: validateRequiredField,
|
||||
email: validateEmailField,
|
||||
};
|
||||
|
||||
mounted() {
|
||||
this.credentials.email = this.email;
|
||||
}
|
||||
|
||||
async resendConfirmationAction(e) {
|
||||
e.preventDefault();
|
||||
this.error = false;
|
||||
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: RESEND_CONFIRMATION_EMAIL,
|
||||
variables: {
|
||||
email: this.credentials.email,
|
||||
},
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.error = true;
|
||||
} finally {
|
||||
this.validationSent = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,92 +0,0 @@
|
||||
<template>
|
||||
<v-container fluid fill-height>
|
||||
<v-layout align-center justify-center>
|
||||
<v-flex xs12 sm8 md4>
|
||||
<v-card class="elevation-12">
|
||||
<v-toolbar dark color="primary">
|
||||
<v-toolbar-title>Password Reset</v-toolbar-title>
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-form @submit="resendConfirmationAction" v-if="!validationSent">
|
||||
<v-text-field
|
||||
label="Email"
|
||||
type="email"
|
||||
v-model="credentials.email"
|
||||
required
|
||||
:state="state.email.status"
|
||||
:rules="[rules.required, rules.email]"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-btn type="submit" color="blue">Reset my password</v-btn>
|
||||
</v-form>
|
||||
<div v-else>
|
||||
<h2>Validation email sent to {{ credentials.email }}</h2>
|
||||
<v-alert :value="true" type="info">Please check you spam folder if you didn't receive the email.</v-alert>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { validateEmailField, validateRequiredField } from '@/utils/validators';
|
||||
import { SEND_RESET_PASSWORD } from '@/graphql/auth';
|
||||
|
||||
@Component
|
||||
export default class SendPasswordReset extends Vue {
|
||||
@Prop({ type: String, required: false, default: '' }) email!: string;
|
||||
|
||||
credentials = {
|
||||
email: '',
|
||||
};
|
||||
validationSent = false;
|
||||
error = false;
|
||||
state = {
|
||||
email: {
|
||||
status: null,
|
||||
msg: '',
|
||||
} as { status: boolean | null, msg: string },
|
||||
};
|
||||
|
||||
rules = {
|
||||
required: validateRequiredField,
|
||||
email: validateEmailField,
|
||||
};
|
||||
|
||||
mounted() {
|
||||
this.credentials.email = this.email;
|
||||
}
|
||||
|
||||
async resendConfirmationAction(e) {
|
||||
e.preventDefault();
|
||||
this.error = false;
|
||||
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: SEND_RESET_PASSWORD,
|
||||
variables: {
|
||||
email: this.credentials.email,
|
||||
},
|
||||
});
|
||||
|
||||
this.validationSent = true;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.error = true;
|
||||
this.state.email = { status: false, msg: err.errors };
|
||||
}
|
||||
}
|
||||
|
||||
resetState() {
|
||||
this.state = {
|
||||
email: {
|
||||
status: null,
|
||||
msg: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<h1 v-if="loading">
|
||||
<translate>Your account is being validated</translate>
|
||||
</h1>
|
||||
<div v-else>
|
||||
<div v-if="failed">
|
||||
<v-alert :value="true" variant="danger">
|
||||
<translate>Error while validating account</translate>
|
||||
</v-alert>
|
||||
</div>
|
||||
<h1 v-else>
|
||||
<translate>Your account has been validated</translate>
|
||||
</h1>
|
||||
</div>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { VALIDATE_USER } from '@/graphql/user';
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { AUTH_TOKEN, AUTH_USER_ID } from '@/constants';
|
||||
|
||||
@Component
|
||||
export default class Validate extends Vue {
|
||||
@Prop({ type: String, required: true }) token!: string;
|
||||
|
||||
loading = true;
|
||||
failed = false;
|
||||
|
||||
created() {
|
||||
this.validateAction();
|
||||
}
|
||||
|
||||
async validateAction() {
|
||||
try {
|
||||
const data = await this.$apollo.mutate({
|
||||
mutation: VALIDATE_USER,
|
||||
variables: {
|
||||
token: this.token,
|
||||
},
|
||||
});
|
||||
|
||||
this.saveUserData(data.data);
|
||||
this.$router.push({ name: 'Home' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.failed = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
saveUserData({ validateUser: login }) {
|
||||
localStorage.setItem(AUTH_USER_ID, login.user.id);
|
||||
localStorage.setItem(AUTH_TOKEN, login.token);
|
||||
}
|
||||
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user