Logged in/ Logged out

- Created midlewares for authenticated and guest]
- Add the token to the api calls
- Added redirect after the login
This commit is contained in:
2020-11-11 20:26:45 +00:00
parent fe1a5d77c3
commit 6945c27ec0
13 changed files with 597 additions and 21 deletions

2
.gitignore vendored
View File

@@ -88,3 +88,5 @@ sw.*
# Vim swap files
*.swp
.idea

View File

@@ -216,7 +216,10 @@
<!-- Sidebar component, swap this element with another sidebar if you like -->
<div class="h-0 flex-1 flex flex-col overflow-y-auto">
<!-- User account dropdown -->
<div class="px-3 mt-6 relative inline-block text-left">
<div
v-if="currentUser.isLoggedIn"
class="px-3 mt-6 relative inline-block text-left"
>
<!-- Dropdown menu toggle, controlling the show/hide state of dropdown menu. -->
<div @click="toggleUserMenu">
<button
@@ -232,7 +235,7 @@
>
<img
class="w-10 h-10 bg-gray-300 rounded-full flex-shrink-0"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=3&w=256&h=256&q=80"
:src="currentUser.profile.picture || ''"
alt=""
/>
<div class="flex-1 min-w-0">
@@ -340,6 +343,9 @@
</div>
</transition>
</div>
<button v-else>
<nuxt-link to="/login">Login</nuxt-link>
</button>
<!-- Sidebar Search -->
<div class="px-3 mt-5">
<label for="search" class="sr-only">Search</label>
@@ -538,7 +544,7 @@
</div>
<div class="flex items-center">
<!-- Profile dropdown -->
<div class="ml-3 relative">
<div class="ml-3 relative" v-if="currentUser.isLoggedIn">
<div>
<button
class="max-w-xs flex items-center text-sm rounded-full focus:outline-none focus:shadow-outline"
@@ -549,7 +555,7 @@
>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
:src="currentUser.profile.picture || ''"
alt=""
/>
</button>
@@ -632,6 +638,9 @@
</div>
</transition>
</div>
<button v-else>
<nuxt-link to="/login">Login</nuxt-link>
</button>
</div>
</div>
</div>
@@ -653,13 +662,37 @@ export default {
sidebarToggled: false,
}
},
computed: {
currentUser() {
return {
isLoggedIn: this.$store.state.auth.loggedIn,
token: this.$store.state.auth.token,
profile: this.$store.state.auth.profile || {picture: ''},
}
},
},
async mounted() {
const loggedIn = await this.$magic.user.isLoggedIn()
const token = await this.$magic.user.getIdToken()
const loggedIn = await this.$magic.user.isLoggedIn().catch((error) => {
console.error(error)
return false
})
const token = await this.$magic.user.getIdToken().catch((error) => {
console.error(error)
return null
})
if (loggedIn) {
const profile = await this.$api.$get('/api/profiles/1').catch(err => {
console.error(err)
return null;
})
if (profile) {
this.$store.commit('auth/setProfile', profile)
} else {
await this.$router.push('/profile/setup')
}
}
this.$store.commit('auth/setToken', token)
this.$store.commit('auth/setLoggedIn', loggedIn)
const d = await this.$api.$get('/api/movies')
console.log({ d })
},
methods: {
toggleUserMenu() {
@@ -673,6 +706,12 @@ export default {
this.$store.commit('auth/setToken', null)
this.$store.commit('auth/setLoggedIn', false)
},
async login() {
const token = await this.$magic.auth.loginWithMagicLink({
email: this.email,
})
this.$store.commit('auth/setToken', token)
},
},
}
</script>

View File

@@ -0,0 +1,6 @@
export default function ({ store, redirect }) {
// If the user is not authenticated
if (!store.state.auth.loggedIn) {
return redirect('/login')
}
}

6
middleware/guest.js Normal file
View File

@@ -0,0 +1,6 @@
export default function ({ store, redirect }) {
// If the user is not authenticated
if (store.state.auth.loggedIn) {
return redirect('/')
}
}

View File

@@ -1,7 +1,7 @@
export default {
// Global page headers (https://go.nuxtjs.dev/config-head)
head: {
title: 'comedy-video',
titleTemplate: 'ComedyLib: %s',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },

178
package-lock.json generated
View File

@@ -2932,6 +2932,11 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"blueimp-md5": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.18.0.tgz",
"integrity": "sha512-vE52okJvzsVWhcgUHOv+69OG3Mdg151xyn41aVQN/5W5S+S43qZhxECtYLAEHMSFWX6Mv5IZrzj3T5+JqXfj5Q=="
},
"bn.js": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
@@ -3612,6 +3617,46 @@
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
}
}
},
"coa": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
@@ -4299,6 +4344,11 @@
"ms": "2.1.2"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@@ -4614,6 +4664,11 @@
}
}
},
"email-validator": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz",
"integrity": "sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ=="
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -6262,6 +6317,11 @@
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-intrinsic": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
@@ -6371,6 +6431,17 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"gravatar": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/gravatar/-/gravatar-1.8.1.tgz",
"integrity": "sha512-18frnfVp4kRYkM/eQW32Mfwlsh/KMbwd3S6nkescBZHioobflFEFHsvM71qZAkUSLNifyi2uoI+TuGxJAnQIOA==",
"requires": {
"blueimp-md5": "^2.16.0",
"email-validator": "^2.0.4",
"querystring": "0.2.0",
"yargs": "^15.4.1"
}
},
"gzip-size": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
@@ -10997,6 +11068,16 @@
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -11251,6 +11332,11 @@
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
"integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0="
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
@@ -13439,6 +13525,11 @@
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"which-pm-runs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
@@ -13672,6 +13763,93 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
"dev": true
},
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"dependencies": {
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"requires": {
"p-locate": "^4.1.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"requires": {
"p-limit": "^2.2.0"
}
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
}
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
}

View File

@@ -19,6 +19,7 @@
"@splidejs/vue-splide": "^0.3.5",
"@tailwindcss/ui": "^0.7.2",
"core-js": "^3.6.5",
"gravatar": "^1.8.1",
"magic-sdk": "^3.0.1",
"nuxt": "^2.14.6"
},

View File

@@ -190,12 +190,13 @@ export default {
splideOptions: {
lazyLoad: 'nearby',
cover: true,
type: 'loop',
// type: 'loop',
// padding: {
// right: '5rem',
// left: '5rem',
// },
perPage: 4,
perMove: 1,
// rewind: false,
breakpoints: {
640: {

188
pages/login.vue Normal file
View File

@@ -0,0 +1,188 @@
<template>
<!--
Tailwind UI components require Tailwind CSS v1.8 and the @tailwindcss/ui plugin.
Read the documentation to get started: https://tailwindui.com/documentation
-->
<div
class="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8"
>
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<img
class="mx-auto h-12 w-auto"
src="https://tailwindui.com/img/logos/v1/workflow-mark-on-white.svg"
alt="Workflow"
/>
<h2
class="mt-6 text-center text-3xl leading-9 font-extrabold text-gray-900"
>
Sign in to your account
</h2>
<!-- <p class="mt-2 text-center text-sm leading-5 text-gray-600 max-w">
Or
<a
href="#"
class="font-medium text-indigo-600 hover:text-indigo-500 focus:outline-none focus:underline transition ease-in-out duration-150"
>
start your 14-day free trial
</a>
</p> -->
</div>
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<form action="#" method="POST" @submit.prevent="login">
<div>
<label
for="email"
class="block text-sm font-medium leading-5 text-gray-700"
>
Email address
</label>
<div class="mt-1 rounded-md shadow-sm">
<input
id="email"
type="email"
v-model="email"
required
class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/>
</div>
</div>
<div class="mt-6">
<span class="block w-full rounded-md shadow-sm">
<button
:disabled="!formValid"
type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out"
>
Sign in
</button>
</span>
</div>
</form>
<div class="mt-6">
<div class="relative">
<div class="absolute inset-0 flex items-center">
<div class="w-full border-t border-gray-300"></div>
</div>
<div class="relative flex justify-center text-sm leading-5">
<span class="px-2 bg-white text-gray-500">
Or continue with
</span>
</div>
</div>
<div class="mt-6 grid grid-cols-3 gap-3">
<div>
<span class="w-full inline-flex rounded-md shadow-sm">
<button
type="button"
class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md bg-white text-sm leading-5 font-medium text-gray-500 hover:text-gray-400 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition duration-150 ease-in-out"
aria-label="Sign in with Facebook"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M20 10c0-5.523-4.477-10-10-10S0 4.477 0 10c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V10h2.54V7.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V10h2.773l-.443 2.89h-2.33v6.988C16.343 19.128 20 14.991 20 10z"
clip-rule="evenodd"
/>
</svg>
</button>
</span>
</div>
<div>
<span class="w-full inline-flex rounded-md shadow-sm">
<button
type="button"
class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md bg-white text-sm leading-5 font-medium text-gray-500 hover:text-gray-400 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition duration-150 ease-in-out"
aria-label="Sign in with Twitter"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
d="M6.29 18.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0020 3.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.073 4.073 0 01.8 7.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 010 16.407a11.616 11.616 0 006.29 1.84"
/>
</svg>
</button>
</span>
</div>
<div>
<span class="w-full inline-flex rounded-md shadow-sm">
<button
type="button"
class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md bg-white text-sm leading-5 font-medium text-gray-500 hover:text-gray-400 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition duration-150 ease-in-out"
aria-label="Sign in with GitHub"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M10 0C4.477 0 0 4.484 0 10.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0110 4.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.203 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.942.359.31.678.921.678 1.856 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0020 10.017C20 4.484 15.522 0 10 0z"
clip-rule="evenodd"
/>
</svg>
</button>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
middleware: 'guest',
head() {
return {
title: 'Login',
}
},
data() {
return {
email: '',
}
},
beforeCreate() {
if (this.$store.state.auth.loggedIn) {
const redFrom = this.$store.state.routing.redirectedFrom
this.$store.commit('routing/setRedirectedFrom', null)
this.$router.push(redFrom || '/')
}
},
computed: {
formValid() {
return this.email ? this.email.trim().length > 0 : false
},
},
methods: {
async login() {
const token = await this.$magic.auth.loginWithMagicLink({
email: this.email,
})
this.$store.commit('auth/setToken', token)
this.$store.commit('auth/setLoggedIn', token !== null)
if (token) {
const profile = await this.$api.$get('/api/profiles/1').catch((err) => {
console.log(err)
return null
})
if (!profile) {
await this.$router.push('/profile/setup')
} else {
this.$store.commit('auth/setProfile', profile)
await this.$router.push('/')
}
}
},
},
}
</script>
<style lang="scss" scoped>
</style>

92
pages/profile/setup.vue Normal file
View File

@@ -0,0 +1,92 @@
<template>
<!--
Tailwind UI components require Tailwind CSS v1.8 and the @tailwindcss/ui plugin.
Read the documentation to get started: https://tailwindui.com/documentation
-->
<div class="min-h-screen bg-gray-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<img class="mx-auto h-12 w-auto" src="https://tailwindui.com/img/logos/v1/workflow-mark-on-white.svg" alt="Workflow">
<h2 class="mt-6 text-center text-3xl leading-9 font-extrabold text-gray-900">
Setup your profile
</h2>
</div>
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<form action="#" method="POST" @submit.prevent="submit">
<div>
<label for="name" class="block text-sm font-medium leading-5 text-gray-700">
Display Name
</label>
<div class="mt-1 rounded-md shadow-sm">
<input v-model="displayName" id="name" type="text" required class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>
<div class="mt-6">
<label for="password" class="block text-sm font-medium leading-5 text-gray-700">
Password
</label>
<div class="mt-1 rounded-md shadow-sm">
<input id="password" type="password" required class="appearance-none block w-full px-3 py-2 border border-gray-300 rounded-md placeholder-gray-400 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>
<div class="mt-6">
<span class="block w-full rounded-md shadow-sm">
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
Save
</button>
</span>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Setup',
head() {
return {
title: 'Profile Setup'
}
},
data() {
return {
displayName: '',
selectedCategories: [],
categories: [
{id:1, name: 'Sport'},
{id:2, name: 'Comedy'},
{id:3, name: 'News'},
]
}
},
beforeCreate() {
if (!this.$store.state.auth.loggedIn) {
this.$router.push('/login')
}
},
methods: {
async submit() {
const profile = await this.$api.$post('/api/profiles', {
displayName: this.displayName
})
console.log(profile)
if (profile) {
this.$store.commit('auth/setProfile', profile.profile)
this.$router.push('/')
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,4 +1,4 @@
export default function ({ $axios }, inject) {
export default function ({ $axios, store }, inject) {
// Create a custom axios instance
const api = $axios.create({
headers: {
@@ -11,6 +11,28 @@ export default function ({ $axios }, inject) {
// Set baseURL to something different
api.setBaseURL(process.env.baseApiUrl)
api.onRequest(config => {
config.headers = {
...config.headers,
Authorization: store.state.auth.token
}
})
// Inject to context as $api
inject('api', api)
}
// export default function ({ $axios, redirect }) {
// $axios.s
// $axios.onRequest(config => {
// console.log('Making request to ' + config.url)
// })
//
// $axios.onError(error => {
// const code = parseInt(error.response && error.response.status)
// if (code === 400) {
// redirect('/400')
// }
// })
// }

View File

@@ -1,22 +1,54 @@
import { createServer } from 'miragejs'
import { createServer, Model } from 'miragejs'
const gravatar = require('gravatar')
if (process.env.NODE_ENV === 'development') {
startServer(0)
// startServer()
}
function startServer() {
createServer({
models: {
video: Model,
profile: Model,
category: Model
},
seeds(server) {
server.create("video", {title: "Awesome video", thumbnail: "https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=1024&h=1024&q=80"})
server.createList("video", 10, {thumbnail: "https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=8&w=1024&h=1024&q=80"})
server.create("category", {name: "Sports"})
server.createList("category", 21)
},
routes() {
this.namespace = 'api'
this.get('/movies', () => {
return {
movies: [
{ id: 1, name: 'Inception', year: 2010 },
{ id: 2, name: 'Interstellar', year: 2014 },
{ id: 3, name: 'Dunkirk', year: 2017 },
],
}
this.get('/videos', (schema) => {
return schema.videos.all()
})
this.get('/profiles', (schema) => {
return schema.profiles.all()
})
this.get('/profiles/:id', (schema, request) => {
let id = request.params.id
return schema.profiles.find(id)
})
this.post('/profiles', (schema, request) => {
let attrs = JSON.parse(request.requestBody)
attrs.id = schema.profiles.all().length + 1
attrs.email = 'testEmail@yopmail.com'
attrs.picture = gravatar.url(attrs.email)
return { profile: attrs }
})
this.get('/categories', (schema, request) => {
return schema.categories.all()
})
},
})

9
store/routing.js Normal file
View File

@@ -0,0 +1,9 @@
export const state = () => ({
redirectedFrom: null
})
export const mutations = {
setRedirectedFrom(state, from) {
state.redirectedFrom = from
}
}