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:
parent
759a740625
commit
90fd0ff6b6
@ -37,7 +37,7 @@ translations: ./$(OUTPUT_DIR)/translations.json
|
||||
mkdir -p $(dir $@)
|
||||
which gettext-extract
|
||||
# Extract gettext strings from templates files and create a POT dictionary template.
|
||||
gettext-extract --attribute v-translate --quiet --output $@ $(GETTEXT_HTML_SOURCES)
|
||||
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 \
|
||||
|
936
js/package-lock.json
generated
936
js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,8 @@
|
||||
"analyze-bundle": "npm run build -- --report-json && webpack-bundle-analyzer ../priv/static/report.json",
|
||||
"dev": "vue-cli-service serve",
|
||||
"test:e2e": "vue-cli-service test:e2e",
|
||||
"test:unit": "vue-cli-service test:unit"
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"prepare": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo-absinthe-upload-link": "^1.4.0",
|
||||
@ -17,6 +18,7 @@
|
||||
"apollo-link": "^1.2.6",
|
||||
"apollo-link-http": "^1.5.9",
|
||||
"apollo-link-state": "^0.4.2",
|
||||
"buefy": "^0.7.1",
|
||||
"easygettext": "^2.7.0",
|
||||
"graphql": "^14.1.1",
|
||||
"graphql-tag": "^2.10.1",
|
||||
@ -32,8 +34,6 @@
|
||||
"vue-markdown": "^2.2.4",
|
||||
"vue-property-decorator": "^7.2.0",
|
||||
"vue-router": "^3.0.2",
|
||||
"vuetify": "^1.3.9",
|
||||
"vuetify-google-autocomplete": "^2.0.0-beta.5",
|
||||
"vuex": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -51,6 +51,7 @@
|
||||
"chai": "^4.2.0",
|
||||
"dotenv-webpack": "^1.5.7",
|
||||
"node-sass": "^4.10.0",
|
||||
"patch-package": "^5.1.1",
|
||||
"sass-loader": "^7.1.0",
|
||||
"tslint-config-airbnb": "^5.11.1",
|
||||
"typescript": "^3.0.0",
|
||||
|
41
js/patches/easygettext+2.7.0.patch
Normal file
41
js/patches/easygettext+2.7.0.patch
Normal file
@ -0,0 +1,41 @@
|
||||
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);
|
||||
}
|
@ -1,17 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>mobilizon</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but mobilizon doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
<html class="has-navbar-fixed-top">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link rel="stylesheet" href="//cdn.materialdesignicons.com/2.5.94/css/materialdesignicons.min.css">
|
||||
<title>mobilizon</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but mobilizon doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
</html>
|
222
js/src/App.vue
222
js/src/App.vue
@ -1,152 +1,19 @@
|
||||
<template>
|
||||
<v-app id="libre-event">
|
||||
<v-navigation-drawer
|
||||
light
|
||||
clipped
|
||||
fixed
|
||||
app
|
||||
v-model="drawer"
|
||||
enable-resize-watcher
|
||||
>
|
||||
<v-list dense>
|
||||
<v-list-group
|
||||
value="false"
|
||||
>
|
||||
<v-list-tile avatar v-if="actor" slot="activator">
|
||||
<v-list-tile-avatar>
|
||||
<img v-if="!actor.avatar"
|
||||
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.avatar"
|
||||
>
|
||||
</v-list-tile-avatar>
|
||||
|
||||
<v-list-tile-content @click="$router.push({name: 'Account', params: { name: actor.username }})">
|
||||
<v-list-tile-title>{{ this.displayed_name }}</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
|
||||
<v-list-tile avatar v-if="actor">
|
||||
<v-list-tile-avatar>
|
||||
<img
|
||||
class="img-circle elevation-7 mb-1"
|
||||
src="https://picsum.photos/125/125/"
|
||||
>
|
||||
</v-list-tile-avatar>
|
||||
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Autre identité</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
|
||||
<v-list-tile @click="$router.push({ name: 'Identities' })">
|
||||
<v-list-tile-action>
|
||||
<v-icon>group</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>Identities</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</v-list-group>
|
||||
<template v-for="(item, i) in items" v-if="showMenuItem(item.role)">
|
||||
<v-layout
|
||||
row
|
||||
v-if="item.heading"
|
||||
align-center
|
||||
:key="i"
|
||||
>
|
||||
<v-flex xs6>
|
||||
<v-subheader v-if="item.heading">
|
||||
{{ item.heading }}
|
||||
</v-subheader>
|
||||
</v-flex>
|
||||
<v-flex xs6 class="text-xs-center">
|
||||
<a href="#!" class="body-2 black--text">EDIT</a>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-list-tile v-bind:key="item.route" v-else @click="$router.push({ name: item.route })">
|
||||
<v-list-tile-action>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
</v-list-tile-action>
|
||||
<v-list-tile-content>
|
||||
<v-list-tile-title>
|
||||
{{ item.text }}
|
||||
</v-list-tile-title>
|
||||
</v-list-tile-content>
|
||||
</v-list-tile>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
<NavBar v-bind="{toggleDrawer}"></NavBar>
|
||||
<v-content>
|
||||
<v-container fluid fill-height :class="{'px-0': $vuetify.breakpoint.xsOnly }">
|
||||
<v-layout xs12>
|
||||
<transition name="router">
|
||||
<router-view></router-view>
|
||||
</transition>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-content>
|
||||
<v-speed-dial
|
||||
v-model="fab"
|
||||
bottom
|
||||
right
|
||||
fixed
|
||||
direction="top"
|
||||
open-on-hover
|
||||
transition="scale-transition"
|
||||
v-if="currentUser"
|
||||
>
|
||||
<v-btn
|
||||
slot="activator"
|
||||
v-model="fab"
|
||||
color="blue darken-2"
|
||||
dark
|
||||
fab
|
||||
>
|
||||
<v-icon>add</v-icon>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
fab
|
||||
dark
|
||||
small
|
||||
color="pink"
|
||||
@click="$router.push({name: 'CreateEvent'})"
|
||||
>
|
||||
<v-icon>event</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
fab
|
||||
dark
|
||||
small
|
||||
color="purple"
|
||||
@click="$router.push({name: 'CreateGroup'})"
|
||||
>
|
||||
<v-icon>group</v-icon>
|
||||
</v-btn>
|
||||
</v-speed-dial>
|
||||
<v-footer class="indigo" app>
|
||||
<span
|
||||
class="white--text"
|
||||
v-translate="{
|
||||
date: new Date().getFullYear(),
|
||||
}">© The Mobilizon Contributors %{date} - Made with Elixir, Phoenix & <a href="https://vuejs.org/">VueJS</a> & <a
|
||||
href="https://www.vuetifyjs.com/">Vuetify</a> with some love and some weeks
|
||||
</span>
|
||||
</v-footer>
|
||||
<v-snackbar
|
||||
:timeout="error.timeout"
|
||||
:error="true"
|
||||
v-model="error.show"
|
||||
>
|
||||
{{ error.text }}
|
||||
<v-btn dark flat @click.native="error.show = false">Close</v-btn>
|
||||
</v-snackbar>
|
||||
</v-app>
|
||||
<div id="mobilizon">
|
||||
<NavBar></NavBar>
|
||||
<main class="container">
|
||||
<router-view></router-view>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<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>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -163,31 +30,40 @@ import { ICurrentUser } from '@/types/current-user.model'
|
||||
}
|
||||
},
|
||||
components: {
|
||||
NavBar,
|
||||
},
|
||||
NavBar
|
||||
}
|
||||
})
|
||||
export default class App extends Vue {
|
||||
drawer = false;
|
||||
fab = false;
|
||||
items = [
|
||||
{
|
||||
icon: 'poll', text: 'Events', route: 'EventList', role: null,
|
||||
icon: "poll",
|
||||
text: "Events",
|
||||
route: "EventList",
|
||||
role: null
|
||||
},
|
||||
{
|
||||
icon: 'group', text: 'Groups', route: 'GroupList', role: null,
|
||||
icon: "group",
|
||||
text: "Groups",
|
||||
route: "GroupList",
|
||||
role: null
|
||||
},
|
||||
{
|
||||
icon: 'content_copy', text: 'Categories', route: 'CategoryList', role: 'ROLE_ADMIN',
|
||||
icon: "content_copy",
|
||||
text: "Categories",
|
||||
route: "CategoryList",
|
||||
role: "ROLE_ADMIN"
|
||||
},
|
||||
{ icon: 'settings', text: 'Settings', role: 'ROLE_USER' },
|
||||
{ icon: 'chat_bubble', text: 'Send feedback', role: 'ROLE_USER' },
|
||||
{ icon: 'help', text: 'Help', role: null },
|
||||
{ icon: 'phonelink', text: 'App downloads', role: null },
|
||||
{ icon: "settings", text: "Settings", role: "ROLE_USER" },
|
||||
{ icon: "chat_bubble", text: "Send feedback", role: "ROLE_USER" },
|
||||
{ icon: "help", text: "Help", role: null },
|
||||
{ icon: "phonelink", text: "App downloads", role: null }
|
||||
];
|
||||
error = {
|
||||
timeout: 3000,
|
||||
show: false,
|
||||
text: '',
|
||||
text: ""
|
||||
};
|
||||
currentUser!: ICurrentUser;
|
||||
|
||||
@ -199,21 +75,21 @@ export default class App extends Vue {
|
||||
|
||||
get displayed_name () {
|
||||
// FIXME: load actor
|
||||
return 'no implemented';
|
||||
return "no implemented";
|
||||
// return this.actor.display_name === null ? this.actor.username : this.actor.display_name
|
||||
}
|
||||
|
||||
showMenuItem (elem) {
|
||||
showMenuItem(elem) {
|
||||
// FIXME: load actor
|
||||
return false;
|
||||
// return elem !== null && this.user && this.user.roles !== undefined ? this.user.roles.includes(elem) : true
|
||||
}
|
||||
|
||||
getUser () {
|
||||
getUser (): ICurrentUser|false {
|
||||
return this.currentUser.id ? this.currentUser : false;
|
||||
}
|
||||
|
||||
toggleDrawer () {
|
||||
toggleDrawer() {
|
||||
this.drawer = !this.drawer;
|
||||
}
|
||||
|
||||
@ -236,16 +112,18 @@ export default class App extends Vue {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.router-enter-active, .router-leave-active {
|
||||
transition-property: opacity;
|
||||
transition-duration: .25s;
|
||||
}
|
||||
.router-enter-active,
|
||||
.router-leave-active {
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.25s;
|
||||
}
|
||||
|
||||
.router-enter-active {
|
||||
transition-delay: .25s;
|
||||
}
|
||||
.router-enter-active {
|
||||
transition-delay: 0.25s;
|
||||
}
|
||||
|
||||
.router-enter, .router-leave-active {
|
||||
opacity: 0
|
||||
}
|
||||
.router-enter,
|
||||
.router-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -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 |