start ui with login
This commit is contained in:
14
src/App.vue
Normal file
14
src/App.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'vue_signup'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
170
src/assets/css/style.css
Normal file
170
src/assets/css/style.css
Normal file
@@ -0,0 +1,170 @@
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
background: #0069ff;
|
||||
}
|
||||
/* Style the tab */
|
||||
.tab {
|
||||
overflow: hidden;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
/* Style the buttons inside the tab */
|
||||
.tab a {
|
||||
background-color: inherit;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
padding: 14px 16px;
|
||||
transition: 0.3s;
|
||||
font-size: 17px;
|
||||
text-decoration: none;
|
||||
border: 1px solid;
|
||||
}
|
||||
/* Change background color of buttons on hover */
|
||||
.tab a:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
/* Create an active/current tablink class */
|
||||
.tab a.active {
|
||||
background-color: #ccc;
|
||||
}
|
||||
/* Style the tab content */
|
||||
.tabcontent {
|
||||
display: none;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: none;
|
||||
}
|
||||
.loginsuccess-container {
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
width: 80%;
|
||||
box-shadow: beige;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
background: #fff;
|
||||
word-break: break-all;
|
||||
}
|
||||
.main-container {
|
||||
margin-top: 10%;
|
||||
}
|
||||
.box-container {
|
||||
padding: 20px;
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
box-shadow: beige;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
background: #fff;
|
||||
}
|
||||
.heading {
|
||||
text-align: center;
|
||||
font-weight: 300;
|
||||
color: #444;
|
||||
margin: 0 auto 45px;
|
||||
font-size: 35px;
|
||||
line-height: 38px;
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.form-fields, .form-fields button {
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
line-height: 28px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.form-fields input {
|
||||
width: 100%;
|
||||
line-height: 40px;
|
||||
border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #f1f1f1;
|
||||
background: #fff;
|
||||
padding: 0 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.signIn {
|
||||
padding: 10px 32px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
background: #15CD72;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
height: auto;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.createaccount {
|
||||
padding: 15px;
|
||||
background-color: #0069ff;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
padding: 0 32px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.center {
|
||||
text-align: center
|
||||
}
|
||||
.login-choice span {
|
||||
color: #5b6987;
|
||||
display: -ms-grid;
|
||||
display: grid;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
line-height: 40px;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
-ms-grid-columns: minmax(20px,1fr) auto minmax(20px,1fr);
|
||||
grid-template-columns: minmax(20px,1fr) auto minmax(20px,1fr);
|
||||
grid-gap: 19px;
|
||||
}
|
||||
.login-choice span:after, .login-choice span:before {
|
||||
content: "";
|
||||
border-top: 1px solid #e5e8ed;
|
||||
}
|
||||
.signup-buttons {
|
||||
margin-top: 15px;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.facebook-signup, .google-signup {
|
||||
color: #031b4e;
|
||||
background: #f2f8ff;
|
||||
border: 1px solid rgba(0,105,255,.2);
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
margin-top: 0;
|
||||
width: 47.5%;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
position: inherit;
|
||||
}
|
||||
.signup-buttons a {
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
}
|
||||
.signup-buttons svg {
|
||||
left: 16px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.footer, .footer a {
|
||||
text-align: center;
|
||||
color: #fff
|
||||
}
|
||||
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
40
src/components/SocialLogin.vue
Normal file
40
src/components/SocialLogin.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="signup-buttons">
|
||||
<a href="#" class="google-signup" @click.prevent="loginWithGoogle">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true"><title>Google</title><g fill="none" fill-rule="evenodd"><path fill="#4285F4" d="M17.64 9.2045c0-.6381-.0573-1.2518-.1636-1.8409H9v3.4814h4.8436c-.2086 1.125-.8427 2.0782-1.7959 2.7164v2.2581h2.9087c1.7018-1.5668 2.6836-3.874 2.6836-6.615z"></path><path fill="#34A853" d="M9 18c2.43 0 4.4673-.806 5.9564-2.1805l-2.9087-2.2581c-.8059.54-1.8368.859-3.0477.859-2.344 0-4.3282-1.5831-5.036-3.7104H.9574v2.3318C2.4382 15.9832 5.4818 18 9 18z"></path><path fill="#FBBC05" d="M3.964 10.71c-.18-.54-.2822-1.1168-.2822-1.71s.1023-1.17.2823-1.71V4.9582H.9573A8.9965 8.9965 0 0 0 0 9c0 1.4523.3477 2.8268.9573 4.0418L3.964 10.71z"></path><path fill="#EA4335" d="M9 3.5795c1.3214 0 2.5077.4541 3.4405 1.346l2.5813-2.5814C13.4632.8918 11.426 0 9 0 5.4818 0 2.4382 2.0168.9573 4.9582L3.964 7.29C4.6718 5.1627 6.6559 3.5795 9 3.5795z"></path></g></svg>
|
||||
Google
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import router from '@/router/router'
|
||||
import {logWithGoogle} from '@/config/noscomptes'
|
||||
export default {
|
||||
name: 'login_signup_social',
|
||||
mounted () {
|
||||
},
|
||||
methods: {
|
||||
loginWithGoogle () {
|
||||
this.$gAuth
|
||||
.signIn()
|
||||
.then(GoogleUser => {
|
||||
logWithGoogle(GoogleUser.getAuthResponse().id_token)
|
||||
// on success do something
|
||||
console.log('GoogleUser', GoogleUser)
|
||||
let userInfoMapped = {
|
||||
googleId: GoogleUser.wa,
|
||||
firstName: GoogleUser.mt.Re,
|
||||
email: GoogleUser.mt.Xt,
|
||||
oauth_token: GoogleUser.Zb.access_token,
|
||||
}
|
||||
this.$store.commit('setLoginUser', userInfoMapped)
|
||||
router.push('/')
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('error', error)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
146
src/config/google_oAuth.js
Normal file
146
src/config/google_oAuth.js
Normal file
@@ -0,0 +1,146 @@
|
||||
var googleAuth = (function () {
|
||||
function installClient () {
|
||||
var apiUrl = 'https://apis.google.com/js/api.js'
|
||||
return new Promise((resolve) => {
|
||||
var script = document.createElement('script')
|
||||
script.src = apiUrl
|
||||
script.onreadystatechange = script.onload = function () {
|
||||
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
document.getElementsByTagName('head')[0].appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
function initClient (config) {
|
||||
return new Promise((resolve) => {
|
||||
window.gapi.load('auth2', () => {
|
||||
window.gapi.auth2.init(config)
|
||||
.then(() => {
|
||||
resolve(window.gapi)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function Auth () {
|
||||
if (!(this instanceof Auth))
|
||||
return new Auth()
|
||||
this.GoogleAuth = null /* window.gapi.auth2.getAuthInstance() */
|
||||
this.isAuthorized = false
|
||||
this.isInit = false
|
||||
this.prompt = null
|
||||
this.isLoaded = function () {
|
||||
/* eslint-disable */
|
||||
console.warn('isLoaded() will be deprecated. You can use "this.$gAuth.isInit"')
|
||||
return !!this.GoogleAuth
|
||||
}
|
||||
|
||||
this.load = (config, prompt) => {
|
||||
installClient()
|
||||
.then(() => {
|
||||
return initClient(config)
|
||||
})
|
||||
.then((gapi) => {
|
||||
this.GoogleAuth = gapi.auth2.getAuthInstance()
|
||||
this.isInit = true
|
||||
this.prompt = prompt
|
||||
this.isAuthorized = this.GoogleAuth.isSignedIn.get()
|
||||
})
|
||||
}
|
||||
|
||||
this.signIn = (successCallback, errorCallback) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.GoogleAuth) {
|
||||
if (typeof errorCallback === 'function') errorCallback(false)
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
this.GoogleAuth.signIn()
|
||||
.then(googleUser => {
|
||||
if (typeof successCallback === 'function') successCallback(googleUser)
|
||||
this.isAuthorized = this.GoogleAuth.isSignedIn.get()
|
||||
resolve(googleUser)
|
||||
})
|
||||
.catch(error => {
|
||||
if (typeof errorCallback === 'function') errorCallback(error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.getAuthCode = (successCallback, errorCallback) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.GoogleAuth) {
|
||||
if (typeof errorCallback === 'function') errorCallback(false)
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
this.GoogleAuth.grantOfflineAccess({ prompt: this.prompt })
|
||||
.then(function (resp) {
|
||||
if (typeof successCallback === 'function') successCallback(resp.code)
|
||||
resolve(resp.code)
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (typeof errorCallback === 'function') errorCallback(error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.signOut = (successCallback, errorCallback) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.GoogleAuth) {
|
||||
if (typeof errorCallback === 'function') errorCallback(false)
|
||||
reject(false)
|
||||
return
|
||||
}
|
||||
this.GoogleAuth.signOut()
|
||||
.then(() => {
|
||||
if (typeof successCallback === 'function') successCallback()
|
||||
this.isAuthorized = false
|
||||
resolve(true)
|
||||
})
|
||||
.catch(error => {
|
||||
if (typeof errorCallback === 'function') errorCallback(error)
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return new Auth()
|
||||
})()
|
||||
|
||||
function installGoogleAuthPlugin(Vue, options) {
|
||||
//set config
|
||||
let GoogleAuthConfig = null
|
||||
let GoogleAuthDefaultConfig = { scope: 'profile email', discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'] }
|
||||
let prompt = 'select_account'
|
||||
if (typeof options === 'object') {
|
||||
GoogleAuthConfig = Object.assign(GoogleAuthDefaultConfig, options)
|
||||
if (options.scope) GoogleAuthConfig.scope = options.scope
|
||||
if (options.prompt) prompt = options.prompt
|
||||
if (!options.clientId) {
|
||||
console.warn('clientId is required')
|
||||
}
|
||||
} else {
|
||||
console.warn('invalid option type. Object type accepted only')
|
||||
}
|
||||
|
||||
//Install Vue plugin
|
||||
Vue.gAuth = googleAuth
|
||||
Object.defineProperties(Vue.prototype, {
|
||||
$gAuth: {
|
||||
get: function () {
|
||||
return Vue.gAuth
|
||||
}
|
||||
}
|
||||
})
|
||||
Vue.gAuth.load(GoogleAuthConfig, prompt)
|
||||
}
|
||||
|
||||
export default installGoogleAuthPlugin
|
||||
15
src/config/noscomptes.js
Normal file
15
src/config/noscomptes.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
export const logWithGoogle = (oauthToken) => {
|
||||
const headers = {
|
||||
"Authorization": "Bearer "+oauthToken
|
||||
};
|
||||
return Vue.axios.post("http://localhost:8081/users", "{}",{headers})
|
||||
}
|
||||
|
||||
export const getUserInformation = (oauthToken) => {
|
||||
const headers = {
|
||||
"Authorization": "Bearer "+oauthToken
|
||||
};
|
||||
return Vue.axios.get("http://localhost:8081/configuration", {headers})
|
||||
}
|
||||
25
src/config/utils.js
Normal file
25
src/config/utils.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Set localStorage
|
||||
*/
|
||||
export const setStore = (name, content) => {
|
||||
if (!name) return
|
||||
if (typeof content !== 'string') {
|
||||
content = JSON.stringify(content)
|
||||
}
|
||||
return window.localStorage.setItem(name, content)
|
||||
}
|
||||
/**
|
||||
* Get localStorage
|
||||
*/
|
||||
export const getStore = (name) => {
|
||||
if (!name) return
|
||||
return JSON.parse(window.localStorage.getItem(name))
|
||||
}
|
||||
/**
|
||||
* Clear localStorage
|
||||
*/
|
||||
export const removeItem = (name) => {
|
||||
console.log(name)
|
||||
if (!name) return
|
||||
return window.localStorage.removeItem(name)
|
||||
}
|
||||
35
src/main.js
Normal file
35
src/main.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router/router'
|
||||
import store from './store/store'
|
||||
import axios from 'axios'
|
||||
import VueAxios from 'vue-axios'
|
||||
|
||||
import '@/assets/css/style.css'
|
||||
|
||||
import GoogleAuth from '@/config/google_oAuth.js'
|
||||
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
|
||||
|
||||
// Import Bootstrap an BootstrapVue CSS files (order is important)
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||
|
||||
const gauthOption = {
|
||||
clientId: '61386079886-2k3g6793pgt5pha4rhdojpvgrkuccfj7.apps.googleusercontent.com',
|
||||
scope: 'profile email',
|
||||
prompt: 'select_account'
|
||||
}
|
||||
Vue.use(VueAxios, axios)
|
||||
Vue.use(GoogleAuth, gauthOption)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
|
||||
// Make BootstrapVue available throughout your project
|
||||
Vue.use(BootstrapVue)
|
||||
// Optionally install the BootstrapVue icon components plugin
|
||||
Vue.use(IconsPlugin)
|
||||
47
src/router/router.js
Normal file
47
src/router/router.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Home from '@/views/Home'
|
||||
import Login from '@/views/Login'
|
||||
import store from "../store/store";
|
||||
Vue.use(Router)
|
||||
|
||||
let baseRoutes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
name: 'Home',
|
||||
component: Home,
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'Login',
|
||||
component: Login
|
||||
}
|
||||
]
|
||||
|
||||
const router = new Router({
|
||||
mode: 'history',
|
||||
linkExactActiveClass: 'active',
|
||||
base: process.env.BASE_URL,
|
||||
routes: baseRoutes
|
||||
})
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// redirect to login page if not logged in and trying to access a restricted page
|
||||
const publicPages = ['/login']
|
||||
const authRequired = !publicPages.includes(to.path)
|
||||
const loggedIn = store.state.loggedUser
|
||||
console.log(authRequired)
|
||||
console.log(store.state.loggedUser)
|
||||
if (authRequired && !loggedIn) {
|
||||
console.log("Redirected")
|
||||
return next('/login')
|
||||
}
|
||||
next()
|
||||
})
|
||||
|
||||
export default router
|
||||
33
src/store/store.js
Normal file
33
src/store/store.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import { setStore, getStore } from '@/config/utils'
|
||||
import {removeItem} from "../config/utils";
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const user = getStore('user')
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
loggedUser: user
|
||||
},
|
||||
mutations: {
|
||||
setLoginUser(state, user) {
|
||||
state.loggedUser = user
|
||||
setStore('user', user)
|
||||
},
|
||||
deleteLoginUser(state) {
|
||||
console.log("delete user")
|
||||
state.loggedUser = undefined
|
||||
removeItem('user')
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
},
|
||||
getters: {
|
||||
getLoginUserInfo(state) {
|
||||
return state.loginUser
|
||||
}
|
||||
}
|
||||
})
|
||||
59
src/views/Home.vue
Normal file
59
src/views/Home.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-navbar toggleable="lg" type="dark" variant="info" fixed="fixed">
|
||||
<!-- Right aligned nav items -->
|
||||
<b-navbar-nav >
|
||||
<b-nav-item href="#">Mes comptes</b-nav-item>
|
||||
<b-nav-item href="#">Nos comptes</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
<b-navbar-nav align="end" class="right-element">
|
||||
<b-nav-item-dropdown left dropleft>
|
||||
<!-- Using 'button-content' slot -->
|
||||
<template #button-content>
|
||||
<em>{{ $store.state.loggedUser.firstName}}</em>
|
||||
</template>
|
||||
<b-dropdown-item href="#">Profile</b-dropdown-item>
|
||||
<b-dropdown-item @click="signOut" href="/">Sign Out</b-dropdown-item>
|
||||
</b-nav-item-dropdown>
|
||||
</b-navbar-nav>
|
||||
</b-navbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import router from '@/router/router'
|
||||
import {BDropdownItem, BNavbar, BNavbarNav, BNavItem, BNavItemDropdown} from "bootstrap-vue";
|
||||
|
||||
export default {
|
||||
name: 'home',
|
||||
components: {
|
||||
BNavbar,
|
||||
BNavbarNav,
|
||||
BNavItem,
|
||||
BNavItemDropdown,
|
||||
BDropdownItem
|
||||
},
|
||||
methods: {
|
||||
signOut() {
|
||||
this.$gAuth
|
||||
.signOut()
|
||||
.then( () => {
|
||||
this.$store.commit("deleteLoginUser")
|
||||
router.push("/login")
|
||||
})
|
||||
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.right-element {
|
||||
margin-left: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.right-element .dropdown-menu {
|
||||
right: 0px;
|
||||
}
|
||||
</style>
|
||||
22
src/views/Login.vue
Normal file
22
src/views/Login.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<form>
|
||||
<div class="box-container">
|
||||
<h2 class="heading">Sign In with</h2>
|
||||
<SocialLogin />
|
||||
</div>
|
||||
</form>
|
||||
<div class="footer">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SocialLogin from '@/components/SocialLogin'
|
||||
export default {
|
||||
name: 'login',
|
||||
components: {
|
||||
SocialLogin
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user