Skip to content

Instantly share code, notes, and snippets.

@razbakov
Created August 22, 2019 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save razbakov/44bd955a80ce72a15d51efa903316248 to your computer and use it in GitHub Desktop.
Save razbakov/44bd955a80ce72a15d51efa903316248 to your computer and use it in GitHub Desktop.
import Vue from 'vue'
import * as Sentry from '@sentry/browser'
import axios from 'axios'
import _ from 'lodash'
import { Platform, Notify } from 'quasar'
import Firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/messaging'
import moment from 'moment'
export default {
namespaced: true,
state: {
language: '',
uid: null,
user: null,
token: '',
loginPopup: false,
returnUrl: '',
profile: null,
account: null,
searchLocation: {},
pendingAccount: null,
next: undefined
},
mutations: {
nextAction (state, payload) {
state.next = payload
},
pendingAccount (state, payload) {
state.pendingAccount = payload
},
setAccount (state, payload) {
state.account = payload
},
setProfile (state, payload) {
state.profile = payload
},
setLanguage (state, payload) {
state.language = payload
},
setUser (state, payload) {
state.user = payload
if (payload) {
state.uid = payload.uid
} else {
state.uid = null
}
},
setToken (state, payload) {
state.token = payload
}
},
actions: {
setLanguage ({ dispatch, commit, state }, payload) {
if (state.uid) {
dispatch('updateAccount', { language: payload })
}
commit('setLanguage', payload)
},
register ({ state }, payload) {
Vue.gtm.trackEvent({
category: 'Popup',
action: 'Register',
label: payload
})
state.loginPopup = 'register'
},
forgotPassword ({ state }, payload) {
Vue.gtm.trackEvent({
category: 'Popup',
action: 'ForgotPassword',
label: payload
})
state.loginPopup = 'password'
},
login ({ state }, payload) {
Vue.gtm.trackEvent({
category: 'Popup',
action: 'Login',
label: payload
})
state.loginPopup = 'login'
},
async changeSearchLocation ({ state, dispatch, rootState }, payload) {
if (!payload) {
state.searchLocation = null
return
}
if (!payload.name) {
return
}
state.searchLocation = payload
if (state.uid) {
dispatch('updateAccount', { searchLocation: payload })
}
if (!payload.saved) {
const city = await rootState.$db
.collection('cities')
.doc(payload.name)
.get()
if (!city.exists) {
payload.createdBy = state.uid
payload.createdAt = new Date()
rootState.$db
.collection('cities')
.doc(payload.name)
.set(payload)
}
}
},
hideLogin ({ state }) {
state.loginPopup = 'off'
state.returnUrl = ''
},
async signUserUp ({ commit }, payload) {
commit('setLoggingIn', true, { root: true })
commit('clearError', null, { root: true })
commit('pendingAccount', {
firstName: payload.firstName,
lastName: payload.lastName,
gender: payload.gender,
phone: payload.phone,
email: payload.email
})
try {
await Firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
} catch (error) {
commit('setLoggingIn', false, { root: true })
commit('setError', error, { root: true })
}
},
async sendPasswordResetEmail ({ commit }, email) {
commit('setLoggingIn', true, { root: true })
try {
await Firebase.auth().sendPasswordResetEmail(email)
commit('setLoggingIn', false, { root: true })
} catch (error) {
commit('setLoggingIn', false, { root: true })
commit('setError', error, { root: true })
}
},
async signUserIn ({ commit }, payload) {
commit('clearError', null, { root: true })
commit('setLoggingIn', true, { root: true })
try {
await Firebase
.auth()
.signInWithEmailAndPassword(payload.email, payload.password)
} catch (error) {
commit('setLoggingIn', false, { root: true })
commit('setError', error, { root: true })
}
},
signUserInTwiiter ({ commit }) {
commit('clearError', null, { root: true })
commit('setLoggingIn', true, { root: true })
const provider = new Firebase.auth.TwitterAuthProvider()
Firebase.auth().signInWithRedirect(provider)
},
signUserInGoogle ({ commit }) {
commit('clearError', null, { root: true })
commit('setLoggingIn', true, { root: true })
const provider = new Firebase.auth.GoogleAuthProvider()
provider.addScope('https://www.googleapis.com/auth/userinfo.email')
Firebase.auth().signInWithRedirect(provider)
},
async getRedirectResult ({ dispatch, commit }) {
try {
const result = await Firebase.auth().getRedirectResult()
dispatch('loadUser', result.user)
} catch (error) {
commit('setError', error, { root: true })
}
},
signUserInFacebook ({ commit }) {
commit('clearError', null, { root: true })
commit('setLoggingIn', true, { root: true })
const provider = new Firebase.auth.FacebookAuthProvider()
provider.addScope('email')
Firebase.auth().signInWithRedirect(provider)
},
async signInWithEmailLink ({ commit }, payload) {
const email = payload.email
if (!email || email.length < 3) {
return
}
commit('clearError', null, { root: true })
let result
try {
result = await Firebase
.auth()
.signInWithEmailLink(email, payload.link)
} catch (error) {
commit('setError', error, { root: true })
}
console.log('signInWithEmailLink', result, payload)
// commit('setReturnUrl', payload.returnUrl, { root: true })
// commit('setReferrer', payload.referrer, { root: true })
},
async sendSignInLinkToEmail ({ commit, rootState }, payload) {
commit('clearError', null, { root: true })
let url = `${window.location.origin}/user/signin`
let utm = {}
let referrer = ''
let clientId = ''
if (rootState.shared.utm) {
utm = rootState.shared.utm
}
if (rootState.shared.referrer) {
referrer = rootState.shared.referrer
}
if (rootState.shared.clientId) {
clientId = rootState.shared.clientId
}
const params = {
email: payload.email,
clientId,
returnUrl: payload.returnUrl,
referrer,
...utm
}
url += '?' + Object.entries(params).map(([key, val]) => `${key}=${val}`).join('&')
try {
await Firebase
.auth()
.sendSignInLinkToEmail(payload.email, {
url,
handleCodeInApp: true
})
} catch (error) {
commit('setError', error, { root: true })
throw error
}
},
async logout ({ state, commit }) {
if (window && window.dataLayer && state.id) {
window.dataLayer.push({
event: 'logout',
target: 'logout'
})
}
commit('setAccount', null)
commit('setProfile', null)
commit('setUser', null)
await Firebase.auth().signOut()
},
async updateProfile ({ state, rootState, dispatch }, payload) {
await rootState.$db
.collection('profiles')
.doc(state.uid)
.update(payload)
await dispatch('loadProfile')
},
async updateAccount ({ state, rootState, dispatch, commit }, account) {
try {
if (state.account && account && state.account.email !== account.email) {
await dispatch('updateEmail', account.email)
}
if (account.password) {
const user = Firebase.auth().currentUser
await user.updatePassword(account.password)
}
account = _.omit(account, 'password')
await rootState.$db
.collection('users')
.doc(state.uid)
.update(account)
await dispatch('loadAccount')
} catch (error) {
commit('setError', error, { root: true })
await dispatch('loadAccount')
throw error
}
},
async loadAccount ({ rootState, state, commit, dispatch }) {
const doc = await rootState.$db.collection('users').doc(state.uid).get()
const account = doc.data()
account.activated = Boolean(account.email && account.phone && account.gender && account.firstName && account.lastName)
commit('setAccount', account)
await dispatch('loadProfile')
},
sendNotification ({ state }, notification) {
if (!notification.to.token) {
return
}
axios({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'post',
headers: {
Authorization: `key=${process.env.VUE_APP_GOOGLE_SERVER_KEY}`
},
data: {
notification: {
title: notification.title,
body: notification.message,
icon: state.profile.avatar,
click_action: `${process.env.VUE_APP_BASE_URI}/chat/${state.uid}`
},
to: notification.to.token
}
})
},
initMessages ({ dispatch, rootState }) {
if (Firebase.messaging.isSupported()) {
Firebase.messaging().usePublicVapidKey(
process.env.VUE_APP_GOOGLE_MESSAGING_KEY
)
Firebase.messaging().onMessage(function (payload) {
Notify.create({
type: 'info',
message: payload.notification.title,
detail: payload.notification.body,
avatar: payload.notification.icon,
actions: [
{
label: 'Reply',
icon: 'chat',
noDismiss: true,
handler: payload.notification.click_action
}
]
})
})
}
if (!Firebase.messaging.isSupported()) {
dispatch('updateAccount', { notifications: false, token: null })
return
}
const messaging = Firebase.messaging()
messaging
.requestPermission()
.then(function () {
dispatch('updateAccount', { notifications: true })
})
.catch(function () {
dispatch('updateAccount', { notifications: false })
})
rootState.shared.notificationsAreRequested = true
messaging
.getToken()
.then(function (currentToken) {
if (currentToken) {
dispatch('updateAccount', { token: currentToken })
} else {
console.log(
'No Instance ID token available. Request permission to generate one.'
)
}
})
.catch(function (err) {
if (err.code === 'messaging/notifications-blocked') {
rootState.shared.notificationsAreBlocked = true
} else {
console.log('An error occurred while retrieving token. ', err)
}
})
messaging.onTokenRefresh(function () {
messaging
.getToken()
.then(function (refreshedToken) {
dispatch('updateAccount', { token: refreshedToken })
})
.catch(function (err) {
console.log('Unable to retrieve refreshed token ', err)
})
})
},
async sendEmailVerification ({ commit }) {
try {
const user = Firebase.auth().currentUser
await user.sendEmailVerification()
} catch (error) {
commit('setError', error, { root: true })
throw error
}
},
async updateEmail ({ commit }, email) {
if (!email) {
return
}
try {
const user = Firebase.auth().currentUser
await user.updateEmail(email)
await user.sendEmailVerification()
} catch (error) {
commit('setError', error, { root: true })
throw error
}
},
async loadProfile ({ state, commit, rootState }) {
const docRef = rootState.$db.collection('profiles').doc(state.uid)
let doc
doc = await docRef.get()
if (!doc.exists) {
const account = state.account
if (!state.account) {
commit('setProfile', null)
return
}
await docRef.set({
id: state.uid,
name: account.name || '',
gender: account.gender || null,
cover: account.cover || '',
avatar: account.avatar || '',
moto: account.moto || '',
gallery: account.gallery || {}
})
doc = await docRef.get()
}
commit('setProfile', doc.data())
},
async loadUser ({ commit, dispatch, rootState, state }, user) {
if (!user || !user.uid) {
return
}
dispatch('hideLogin')
const providerData = user.providerData ? user.providerData[0] : {
email: user.email,
displayName: user.displayName,
providerId: 'email-password'
}
const userDocRef = rootState.$db.collection('users').doc(user.uid)
Sentry.configureScope(scope => {
scope.setUser({
email: providerData.email,
id: user.uid,
name: providerData.displayName
})
})
const doc = await userDocRef.get()
let account = {}
if (doc.exists) {
account = doc.data()
commit('setLanguage', account.language)
if (!state.uid) {
Vue.gtm.trackEvent({
category: 'User',
action: 'Login',
label: providerData ? providerData.providerId : 'unknown'
})
}
} else {
account = { ...state.pendingAccount }
if (account && account.email) {
await dispatch('updateEmail', account.email)
}
Vue.gtm.trackEvent({
category: 'User',
action: 'SignUp',
label: providerData ? providerData.providerId : 'unknown'
})
}
commit('pendingAccount', null)
account.version = rootState.shared.version
account.emailVerified = user.emailVerified
if (account.firstName && account.lastName) {
account.name = `${account.firstName} ${account.lastName}`
} else {
if (!account.name && providerData.displayName) {
account.name = providerData.displayName
}
if (account.name) {
let [firstName, lastName] = [...account.name.split(' ')]
account.firstName = firstName || ''
account.lastName = lastName || ''
}
}
if (!account.email && providerData) {
account.email = providerData.email
}
if (!account.registeredAt) {
account.registeredAt = Date.now()
}
if (!account.daysUsed) {
account.daysUsed = 1
}
if (account.lastLoginAt) {
const isSameDay = moment(account.lastLoginAt).isSame(moment(), 'day')
if (!isSameDay) {
account.daysUsed = account.daysUsed + 1
}
}
account.lastLoginAt = Date.now()
if ((!account.avatar || !account.avatar.includes('firebasestorage')) && providerData.photoURL && providerData.photoURL.includes('facebook')) {
account.avatar = providerData.photoURL + '?height=500'
}
if (!account.provider) {
account.provider = providerData.providerId
}
if (!account.providerUid) {
account.providerUid = providerData.uid
}
account.pwa = window && window.matchMedia('(display-mode: standalone)').matches
account.pwaUsed = account.pwaUsed || account.pwa
account.extra = {
clientId: rootState.shared.clientId,
utm: rootState.shared.utm,
referrer: rootState.shared.referrer,
promo: rootState.shared.promo,
ref: rootState.shared.ref,
userLanguage: window ? window.navigator.userLanguage || '' : '',
systemLanguage: window ? window.navigator.systemLanguage || '' : '',
browserLanguage: window ? window.navigator.browserLanguage || '' : '',
language: window ? window.navigator.language || '' : '',
languages: window ? window.navigator.languages || '' : '',
geo: rootState.shared.geo || '',
location: rootState.shared.location || '',
platform: Platform.is,
userAgent: window ? navigator.userAgent || navigator.vendor || window.opera : ''
}
if (!account.initialExtra) {
account.initialExtra = account.extra
}
await rootState.$db
.collection('users')
.doc(user.uid)
.set(account)
commit('setUser', user)
Sentry.configureScope(scope => {
scope.setUser({
email: account.email,
id: user.uid,
username: account.name,
name: account.name
})
})
await dispatch('loadAccount')
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment