added a lot of auth code and resolved merge conflicht
This commit is contained in:
21
package-lock.json
generated
21
package-lock.json
generated
@@ -2392,6 +2392,15 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.3.0",
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
@@ -5515,7 +5524,6 @@
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
|
||||
"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.2.6"
|
||||
},
|
||||
@@ -5524,7 +5532,6 @@
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
@@ -12830,6 +12837,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.8.tgz",
|
||||
"integrity": "sha512-+vp9lEC2Kt3yom673pzg1J7T1NVGuGzO9j8Wxno+rQN2WYVBX2pyo/RGQ3fXCLh2Pk76Skw/laAPCuBuEQ4diw=="
|
||||
},
|
||||
"vue-axios": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/vue-axios/-/vue-axios-2.1.4.tgz",
|
||||
"integrity": "sha512-DS8Q+WFT3i7nS0aZ/NMmTPf2yhbtlXhj4QEZmY69au/BshsGzGjC6dXaniZaPQlErP3J3Sv1HtQ4RVrXaUTkxA=="
|
||||
},
|
||||
"vue-class-component": {
|
||||
"version": "6.3.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-6.3.2.tgz",
|
||||
@@ -12950,6 +12962,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.0.tgz",
|
||||
"integrity": "sha512-mdHeHT/7u4BncpUZMlxNaIdcN/HIt1GsGG5LKByArvYG/v6DvHcOxvDCts+7SRdCoIRGllK8IMZvQtQXLppDYg=="
|
||||
},
|
||||
"vuex-typex": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/vuex-typex/-/vuex-typex-3.1.4.tgz",
|
||||
"integrity": "sha512-MXW5QBk8Cq01zP5/5cKLp8QQmC5Zp2m/mSZlWLWmmeF6gGT7d1RpQ2zxc0rT4JQkLOYLdZees+yvgjivtBZDLg=="
|
||||
},
|
||||
"w3c-hr-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
|
||||
|
||||
@@ -10,14 +10,17 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/cli": "^3.4.1",
|
||||
"axios": "^0.18.0",
|
||||
"bootstrap-vue": "^2.0.0-rc.13",
|
||||
"vue": "^2.6.6",
|
||||
"vue-axios": "^2.1.4",
|
||||
"vue-class-component": "^6.0.0",
|
||||
"vue-flag-icon": "^1.0.6",
|
||||
"vue-i18n": "^8.9.0",
|
||||
"vue-property-decorator": "^7.0.0",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1"
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-typex": "^3.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.1.0",
|
||||
|
||||
31
src/api/index.ts
Normal file
31
src/api/index.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = 'http://localhost:5443/api';
|
||||
|
||||
export function fetchSurveys () {
|
||||
return axios.get(`${API_URL}/surveys/`)
|
||||
}
|
||||
|
||||
export function fetchSurvey (surveyId: string) {
|
||||
return axios.get(`${API_URL}/surveys/${surveyId}/`)
|
||||
}
|
||||
|
||||
export function saveSurveyResponse (surveyResponse: any) {
|
||||
return axios.put(`${API_URL}/surveys/${surveyResponse.id}/`, surveyResponse)
|
||||
}
|
||||
|
||||
export function postNewSurvey (survey: any, jwt: any) {
|
||||
return axios.post(`${API_URL}/surveys/`, survey, { headers: { Authorization: `Bearer: ${jwt}` } })
|
||||
}
|
||||
|
||||
export function authenticate (userData: any) {
|
||||
return axios.post(`${API_URL}/auth/login`, userData)
|
||||
}
|
||||
|
||||
export function register (userData: any) {
|
||||
return axios.post(`${API_URL}/auth/register`, userData)
|
||||
}
|
||||
|
||||
export function getProviders (providers: any) {
|
||||
return axios.get(`${API_URL}/auth/providers`, providers)
|
||||
}
|
||||
79
src/components/Login.vue
Normal file
79
src/components/Login.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<!-- components/Login.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h2 class="title">Login or Register</h2>
|
||||
<p class="subtitle error-msg">{{ errorMsg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="field">
|
||||
<label class="label is-large" for="email">Email:</label>
|
||||
<div class="control">
|
||||
<input type="email" class="input is-large" id="email" v-model="email">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label is-large" for="password">Password:</label>
|
||||
<div class="control">
|
||||
<input type="password" class="input is-large" id="password" v-model="password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-large is-primary" @click="authenticate">Login</a>
|
||||
<a class="button is-large is-success" @click="register">Register</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { EventBus } from '@/utils'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
email: '',
|
||||
password: '',
|
||||
errorMsg: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
authenticate () {
|
||||
this.$store.dispatch('login', { email: this.email, password: this.password })
|
||||
.then(() => this.$router.push('/'))
|
||||
},
|
||||
register () {
|
||||
this.$store.dispatch('register', { email: this.email, password: this.password })
|
||||
.then(() => this.$router.push('/'))
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
EventBus.$on('failedRegistering', (msg) => {
|
||||
this.errorMsg = msg
|
||||
})
|
||||
EventBus.$on('failedAuthentication', (msg) => {
|
||||
this.errorMsg = msg
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
EventBus.$off('failedRegistering')
|
||||
EventBus.$off('failedAuthentication')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.error-msg {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
75
src/components/NewQuestion.vue
Normal file
75
src/components/NewQuestion.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="field">
|
||||
<label class="label is-large">Question</label>
|
||||
<div class="control">
|
||||
<input type="text" class="input is-large" v-model="question">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<a class="button is-large is-info" @click="addChoice">
|
||||
<span class="icon is-small">
|
||||
<i class="fa fa-plus-square-o fa-align-left" aria-hidden="true"></i>
|
||||
</span>
|
||||
<span>Add choice</span>
|
||||
</a>
|
||||
<a class="button is-large is-primary" @click="saveQuestion">
|
||||
<span class="icon is-small">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
<span>Save</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="label is-large" v-show="choices.length > 0">Question Choices</h2>
|
||||
<div class="field has-addons" v-for="(choice, idx) in choices" v-bind:key="idx">
|
||||
<div class="control choice">
|
||||
<input type="text" class="input is-large" v-model="choices[idx]">
|
||||
</div>
|
||||
<div class="control">
|
||||
<a class="button is-large">
|
||||
<span class="icon is-small" @click.stop="removeChoice(choice)">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
question: '',
|
||||
choices: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
removeChoice (choice) {
|
||||
const idx = this.choices.findIndex(c => c === choice)
|
||||
this.choices.splice(idx, 1)
|
||||
},
|
||||
saveQuestion () {
|
||||
this.$emit('questionComplete', {
|
||||
question: this.question,
|
||||
choices: this.choices.filter(c => !!c)
|
||||
})
|
||||
this.question = ''
|
||||
this.choices = ['']
|
||||
},
|
||||
addChoice () {
|
||||
this.choices.push('')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.choice {
|
||||
width: 90%;
|
||||
}
|
||||
</style>
|
||||
122
src/components/NewSurvey.vue
Normal file
122
src/components/NewSurvey.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h2 class="title">{{ name }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="tabs is-centered is-fullwidth is-large">
|
||||
<ul>
|
||||
<li :class="{'is-active': step == 'name'}" @click="step = 'name'">
|
||||
<a>Name</a>
|
||||
</li>
|
||||
<li :class="{'is-active': step == 'questions'}" @click="step = 'questions'">
|
||||
<a>Questions</a>
|
||||
</li>
|
||||
<li :class="{'is-active': step == 'review'}" @click="step = 'review'">
|
||||
<a>Review</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-half is-offset-one-quarter">
|
||||
|
||||
<div class="name" v-show="step === 'name'">
|
||||
<div class="field">
|
||||
<label class="label is-large" for="name">Survey name:</label>
|
||||
<div class="control">
|
||||
<input type="text" class="input is-large" id="name" v-model="name">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="questions" v-show="step === 'questions'">
|
||||
<new-question v-on:questionComplete="appendQuestion"/>
|
||||
</div>
|
||||
|
||||
<div class="review" v-show="step === 'review'">
|
||||
<ul>
|
||||
<li class="question" v-for="(question, qIdx) in questions" :key="`question-${qIdx}`">
|
||||
<div class="title">
|
||||
{{ question.question }}
|
||||
<span class="icon is-medium is-pulled-right delete-question"
|
||||
@click.stop="removeQuestion(question)">
|
||||
<i class="fa fa-times" aria-hidden="true"></i>
|
||||
</span>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="(choice , cIdx) in question.choices" :key="`choice-${cIdx}`">
|
||||
{{ cIdx + 1 }}. {{ choice }}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="control">
|
||||
<a class="button is-large is-primary" @click="submitSurvey">Submit</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NewQuestion from '@/components/NewQuestion'
|
||||
|
||||
export default {
|
||||
components: { NewQuestion },
|
||||
data () {
|
||||
return {
|
||||
step: 'name',
|
||||
name: '',
|
||||
questions: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
appendQuestion (newQuestion) {
|
||||
this.questions.push(newQuestion)
|
||||
},
|
||||
removeQuestion (question) {
|
||||
const idx = this.questions.findIndex(q => q.question === question.question)
|
||||
this.questions.splice(idx, 1)
|
||||
},
|
||||
submitSurvey () {
|
||||
this.$store.dispatch('submitNewSurvey', {
|
||||
name: this.name,
|
||||
questions: this.questions
|
||||
})
|
||||
.then(() => this.$router.push('/'))
|
||||
.catch((error) => {
|
||||
console.log('Error creating survey', error)
|
||||
this.$router.push('/')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.question {
|
||||
margin: 10px 20px 25px 10px;
|
||||
}
|
||||
|
||||
.delete-question {
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.delete-question:hover {
|
||||
background-color: lightgray;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
115
src/components/Survey.vue
Normal file
115
src/components/Survey.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div>
|
||||
<section class="hero is-primary">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<h2 class="title">{{ survey.name }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
|
||||
<div class="columns">
|
||||
<div class="column is-10 is-offset-1">
|
||||
|
||||
<div
|
||||
v-for="(question, idx) in survey.questions"
|
||||
v-bind:key="question.id"
|
||||
v-show="currentQuestion === idx">
|
||||
|
||||
<div class="column is-offset-3 is-6">
|
||||
<h4 class='title has-text-centered'>{{ question.text }}</h4>
|
||||
</div>
|
||||
<div class="column is-offset-4 is-4">
|
||||
<div class="control">
|
||||
<div v-for="choice in question.choices" v-bind:key="choice.id">
|
||||
<label class="radio">
|
||||
<input type="radio" v-model="question.choice" name="choice" :value="choice.id">
|
||||
{{ choice.text }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="column is-offset-one-quarter is-half">
|
||||
<nav class="pagination is-centered" role="navigation" aria-label="pagination">
|
||||
<a class="pagination-previous" @click.stop="goToPreviousQuestion"><i class="fa fa-chevron-left" aria-hidden="true"></i> Back</a>
|
||||
<a class="pagination-next" @click.stop="goToNextQuestion">Next <i class="fa fa-chevron-right" aria-hidden="true"></i></a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="has-text-centered">
|
||||
<a v-show="surveyComplete" class='button is-large is-focused is-primary' @click="handleSubmit">Submit</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
currentQuestion: 0
|
||||
}
|
||||
},
|
||||
beforeMount () {
|
||||
this.$store.dispatch('loadSurvey', { id: parseInt(this.$route.params.id) })
|
||||
},
|
||||
methods: {
|
||||
goToNextQuestion () {
|
||||
if (this.currentQuestion === this.survey.questions.length - 1) {
|
||||
this.currentQuestion = 0
|
||||
} else {
|
||||
this.currentQuestion++
|
||||
}
|
||||
},
|
||||
goToPreviousQuestion () {
|
||||
if (this.currentQuestion === 0) {
|
||||
this.currentQuestion = this.survey.questions.lenth - 1
|
||||
} else {
|
||||
this.currentQuestion--
|
||||
}
|
||||
},
|
||||
handleSubmit () {
|
||||
this.$store.dispatch('addSurveyResponse')
|
||||
.then(() => this.$router.push('/'))
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
surveyComplete () {
|
||||
if (this.survey.questions) {
|
||||
const numQuestions = this.survey.questions.length
|
||||
const numCompleted = this.survey.questions.filter(q => q.choice).length
|
||||
return numQuestions === numCompleted
|
||||
}
|
||||
return false
|
||||
},
|
||||
survey () {
|
||||
return this.$store.state.currentSurvey
|
||||
},
|
||||
selectedChoice: {
|
||||
get () {
|
||||
const question = this.survey.questions[this.currentQuestion]
|
||||
return question.choice
|
||||
},
|
||||
set (value) {
|
||||
const question = this.survey.questions[this.currentQuestion]
|
||||
this.$store.commit('setChoice', { questionId: question.id, choice: value })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,4 +1,6 @@
|
||||
import Vue from 'vue';
|
||||
import axios from 'axios'
|
||||
import VueAxios from 'vue-axios'
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
@@ -8,6 +10,7 @@ import FlagIcon from 'vue-flag-icon';
|
||||
// following is to avoid missing type definitions
|
||||
// const FlagIcon = require('vue-flag-icon');
|
||||
|
||||
Vue.use(VueAxios, axios)
|
||||
Vue.use(FlagIcon);
|
||||
|
||||
// setup fake backend
|
||||
|
||||
@@ -5,6 +5,11 @@ import NotFound from './views/NotFound.vue';
|
||||
import LoginPage from './views/LoginPage.vue';
|
||||
|
||||
|
||||
import Survey from '@/components/Survey.vue';
|
||||
import NewSurvey from '@/components/NewSurvey.vue';
|
||||
import Login from '@/components/Login.vue';
|
||||
import store from '@/store'
|
||||
|
||||
Vue.use(Router);
|
||||
|
||||
export const router = new Router({
|
||||
@@ -28,6 +33,25 @@ export const router = new Router({
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import(/* webpackChunkName: "about" */ './views/About.vue'),
|
||||
}, {
|
||||
path: '/surveys/:id',
|
||||
name: 'Survey',
|
||||
component: Survey
|
||||
}, {
|
||||
path: '/surveys',
|
||||
name: 'NewSurvey',
|
||||
component: NewSurvey,
|
||||
beforeEnter (to, from, next) {
|
||||
if (!store.getters.isAuthenticated) {
|
||||
next('/login')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
}
|
||||
}, {
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: Login
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
|
||||
111
src/store.ts
111
src/store.ts
@@ -1,25 +1,110 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import { alert } from './store/alert.module';
|
||||
import { account } from './store/account.module';
|
||||
import { users } from './store/users.module';
|
||||
|
||||
// imports of AJAX functions will go here
|
||||
import { fetchSurveys, fetchSurvey, saveSurveyResponse, postNewSurvey, authenticate, register } from '@/api'
|
||||
import { isValidJwt, EventBus } from '@/utils'
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
alert,
|
||||
account,
|
||||
users,
|
||||
},
|
||||
state: {
|
||||
const state = {
|
||||
// single source of data
|
||||
surveys: [],
|
||||
currentSurvey: {},
|
||||
user: {},
|
||||
jwt: ''
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// asynchronous operations
|
||||
loadSurveys (context: any) {
|
||||
return fetchSurveys()
|
||||
.then((response) => {
|
||||
context.commit('setSurveys', { surveys: response.data })
|
||||
})
|
||||
},
|
||||
// @ts-ignore
|
||||
loadSurvey (context: any, { id }) {
|
||||
return fetchSurvey(id)
|
||||
.then((response) => {
|
||||
context.commit('setSurvey', { survey: response.data })
|
||||
})
|
||||
},
|
||||
addSurveyResponse (context: any) {
|
||||
return saveSurveyResponse(context.state.currentSurvey)
|
||||
},
|
||||
mutations: {
|
||||
|
||||
login (context: any, userData: any) {
|
||||
context.commit('setUserData', { userData })
|
||||
return authenticate(userData)
|
||||
.then(response => context.commit('setJwtToken', { jwt: response.data }))
|
||||
.catch(error => {
|
||||
console.log('Error Authenticating: ', error)
|
||||
// @ts-ignore
|
||||
EventBus.emit('failedAuthentication', error)
|
||||
})
|
||||
},
|
||||
actions: {
|
||||
register (context: any, userData: any) {
|
||||
context.commit('setUserData', { userData })
|
||||
return register(userData)
|
||||
.then(context.dispatch('login', userData))
|
||||
.catch(error => {
|
||||
console.log('Error Registering: ', error)
|
||||
// @ts-ignore
|
||||
EventBus.emit('failedRegistering: ', error)
|
||||
})
|
||||
},
|
||||
submitNewSurvey (context: any, survey: any) {
|
||||
return postNewSurvey(survey, context.state.jwt.token)
|
||||
}
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
// isolated data mutations
|
||||
setSurveys (state: any, payload: any) {
|
||||
state.surveys = payload.surveys
|
||||
},
|
||||
});
|
||||
setSurvey (state: any, payload: any) {
|
||||
const nQuestions = payload.survey.questions.length
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
payload.survey.questions[i].choice = null
|
||||
}
|
||||
state.currentSurvey = payload.survey
|
||||
},
|
||||
setChoice (state: any, payload: any) {
|
||||
const { questionId, choice } = payload
|
||||
const nQuestions = state.currentSurvey.questions.length
|
||||
for (let i = 0; i < nQuestions; i++) {
|
||||
if (state.currentSurvey.questions[i].id === questionId) {
|
||||
state.currentSurvey.questions[i].choice = choice
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
setUserData (state: any, payload: any) {
|
||||
console.log('setUserData payload = ', payload)
|
||||
state.userData = payload.userData
|
||||
},
|
||||
setJwtToken (state: any, payload: any) {
|
||||
console.log('setJwtToken payload = ', payload)
|
||||
localStorage.token = payload.jwt.token
|
||||
state.jwt = payload.jwt
|
||||
}
|
||||
}
|
||||
|
||||
const getters = {
|
||||
// reusable data accessors
|
||||
isAuthenticated (state: any) {
|
||||
return isValidJwt(state.jwt.token)
|
||||
}
|
||||
}
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state,
|
||||
actions,
|
||||
mutations,
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
||||
|
||||
15
src/utils/index.ts
Normal file
15
src/utils/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// utils/index.js
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
export const EventBus = new Vue();
|
||||
|
||||
export function isValidJwt (jwt: any) {
|
||||
if (!jwt || jwt.split('.').length < 3) {
|
||||
return false
|
||||
}
|
||||
const data = JSON.parse(atob(jwt.split('.')[1]));
|
||||
const exp = new Date(data.exp * 1000);
|
||||
const now = new Date();
|
||||
return now < exp;
|
||||
}
|
||||
Reference in New Issue
Block a user