Skip to content

Instantly share code, notes, and snippets.

@huogerac
Created June 7, 2018 03:34
Show Gist options
  • Select an option

  • Save huogerac/448885edb6d3c0690b2ae57bcde2a499 to your computer and use it in GitHub Desktop.

Select an option

Save huogerac/448885edb6d3c0690b2ae57bcde2a499 to your computer and use it in GitHub Desktop.

Revisions

  1. huogerac created this gist Jun 7, 2018.
    89 changes: 89 additions & 0 deletions HomeView.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,89 @@
    <template>

    <div>

    <!-- componente que encapsula o PUSH NOTIFICATION -->
    <push-notification
    ref="pushNotification"
    :currentToken="userToken"
    @update-token="onUpdateToken"
    @new-message="onNewMessage" />

    <!-- snackbar que mostra as notifications -->
    <div id="snackbar-message" class="mdl-js-snackbar mdl-snackbar">
    <div class="mdl-snackbar__text"></div>
    <button class="mdl-snackbar__action" type="button"></button>
    </div>

    <div class="mdl-grid">
    <div class="mdl-cell mdl-cell--3-col mdl-cell mdl-cell--1-col-tablet mdl-cell--hide-phone"></div>
    <div class="mdl-cell mdl-cell--6-col mdl-cell--4-col-phone">

    <!-- mostra uma mensagem amigável para que o visitante que faça o usuário ter vontade de habilitar as
    notificaçes -->
    <div v-show="askForPermission && !userToken" class="headline" style="background-color: #ff897d; padding: 20px; border-radius: 6px; color: #fff;">
    Hey, click here to start receiving our amazing push notifications!!!
    <button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect"
    @click="enableNotifications">
    Enable notifications
    </button>
    </div>

    </div>
    </div>
    </div>
    </template>

    <script>
    import PushNotification from '@/components/PushNotification'
    import api from '@/api/api'
    export default {
    components: {
    PushNotification
    },
    methods: {
    enableNotifications () {
    this.$refs.pushNotification.askForPermission()
    },
    onUpdateToken (newToken) {
    this.userToken = newToken
    // send token to the server
    api.update_token(this.userProfile, this.userToken)
    },
    onNewMessage (message) {
    var snackbarContainer = document.querySelector('#snackbar-message')
    var data = {
    message: message.notification.title + ': ' + message.notification.body,
    timeout: 10000,
    actionText: 'OK'
    }
    snackbarContainer.MaterialSnackbar.showSnackbar(data)
    }
    },
    created () {
    var userLoggedId = 1
    // check if user has a token
    api.user_profile(userLoggedId).then((response) => {
    this.userProfile = response.data
    this.userToken = this.userProfile.push_notification.ask_for_permission.token
    if (this.userProfile.push_notification.ask_for_permission) {
    setTimeout(() => {
    // Simulate it wont ask for permission in the first user access
    this.askForPermission = true
    }, 4000)
    }
    })
    },
    data () {
    return {
    userProfile: {},
    askForPermission: false,
    userToken: null
    }
    }
    }
    </script>

    <style scoped>
    </style>
    59 changes: 59 additions & 0 deletions PushNotification.vue
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    <template>
    </template>

    <script>
    import firebase from '../service/firebase'
    export default {
    props: ['currentToken'],
    data () {
    return {
    hasServiceWorker: false
    }
    },
    mounted () {
    this.initialize()
    },
    methods: {
    initialize () {
    if (!('serviceWorker' in navigator)) {
    console.warn('serviceWorker not working')
    return
    }
    if (!('PushManager' in window)) {
    console.warn('PushManager not working')
    return
    }
    this.hasServiceWorker = true
    },
    askForPermission () {
    if (!this.hasServiceWorker) {
    return
    }
    // console.firebase | project settins | cloud message | web config | Key pair
    firebase.messaging.usePublicVapidKey('BK8JSwxoV2WXvivBQ0deKPy9PVTRaYcYmuwGjJWGpgTAZ7-NM48H1ScVsO6EvMhP7O9jhSGp39XFtRQCPgfDAJI')
    navigator.serviceWorker.register('./static/firebase-messaging-sw.js')
    .then((registration) => {
    firebase.messaging.useServiceWorker(registration)
    firebase.messaging.requestPermission().then(() => {
    firebase.messaging.getToken().then((token) => {
    if (token !== this.currentToken) {
    this.$emit('update-token', token)
    }
    }).catch((err) => console.log('--- token error:', err))
    }).catch(function (err) {
    console.log('Unable to get permission to notify.', err)
    })
    }).catch(err => {
    console.log('error register', err)
    })
    firebase.messaging.onMessage((payload) => {
    this.$emit('new-message', payload)
    })
    }
    }
    }
    </script>
    45 changes: 45 additions & 0 deletions api_mock.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    /* eslint-disable */

    export default {
    user_profile: _mockasync(user_profile),
    update_token: _mockasync(update_token)
    }

    /**
    * Get the user profile from the backend
    * @param ask_for_permission: it IS NOT a good idea ask for ALLOW push notifications in the first time the user gets in the website.
    * perhaps after he browsers or watch the first video.
    * @param token: after the user gives permission (ALLOW), the firebase send a token which will be used to send message for the user device.
    */
    function user_profile(user_id) {
    return {
    user_id: user_id,
    push_notification: {
    ask_for_permission: true,
    token: null
    }
    }
    }


    /**
    * If the user clear data or change the computer etc..he will receive a new token from the firebase messaging.
    * So we need to keep the backend updated
    * @param token: new token
    */
    function update_token(user_profile, token) {
    user_profile.push_notification.token = token
    return user_profile
    }

    function _mockasync(f){
    function mocked(){
    var res = f.apply(this, arguments)
    return new Promise(function(resolve, reject){
    setTimeout(function(){
    resolve({data: res})
    }, 600);
    })
    }
    return mocked
    }
    16 changes: 16 additions & 0 deletions firebase-messaging-sw.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    // /static/firebase-messaging-sw.js
    importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-app.js')
    importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-messaging.js')

    var config = {
    apiKey: 'AIzaSyABRALdPhSmLH_NdwxQ27gcwG-_v9QacV4',
    authDomain: 'evolutiodev.firebaseapp.com',
    databaseURL: 'https://evolutiodev.firebaseio.com/',
    projectId: 'evolutiodev',
    storageBucket: 'evolutiodev.appspot.com',
    messagingSenderId: '646469414520'
    }

    firebase.initializeApp(config)

    const messaging = firebase.messaging()
    16 changes: 16 additions & 0 deletions firebase.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    import firebase from 'firebase'

    var config = {
    apiKey: 'AIzaSyABRALdPhSmLH_NdwxQ27gcwG-_v9QacV4',
    authDomain: 'evolutiodev.firebaseapp.com',
    databaseURL: 'https://evolutiodev.firebaseio.com/',
    projectId: 'evolutiodev',
    storageBucket: 'evolutiodev.appspot.com',
    messagingSenderId: '646469414520'
    }

    firebase.initializeApp(config)

    export default {
    messaging: firebase.messaging()
    }
    17 changes: 17 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Push Notifications</title>
    <!-- ADD THIS -->
    <link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath %>static/manifest.json">
    ...
    </head>
    <body>
    ... the latest VueJs Template already has this service worker
    <%= htmlWebpackPlugin.options.serviceWorkerLoader %>

    </body>
    </html>
    20 changes: 20 additions & 0 deletions main.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    // The Vue build version to load with the `import` command
    // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import VueResource from 'vue-resource'
    import VueFire from 'vuefire'

    Vue.config.productionTip = false

    Vue.use(VueResource)
    Vue.use(VueFire)

    /* eslint-disable no-new */
    new Vue({
    el: '#app',
    router,
    template: '<App/>',
    components: { App }
    })
    32 changes: 32 additions & 0 deletions manifest.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    {
    "name": "cropchat",
    "short_name": "cropchat",
    "gcm_sender_id": "103953800507",
    "icons": [
    {
    "src": "/static/img/icons/cropchat-icon-64x64.png",
    "sizes": "192x192",
    "type": "image/png"
    },
    {
    "src": "/static/img/icons/cropchat-icon-128x128.png",
    "sizes": "128x128",
    "type": "image/png"
    },
    {
    "src": "/static/img/icons/cropchat-icon-256x256.png",
    "sizes": "256x256",
    "type": "image/png"
    },
    {
    "src": "/static/img/icons/cropchat-icon-512x512.png",
    "sizes": "512x512",
    "type": "image/png"
    }
    ],
    "start_url": "/",
    "display": "fullscreen",
    "orientation": "portrait",
    "background_color": "#2196f3",
    "theme_color": "#2196f3"
    }
    99 changes: 99 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    {
    "name": "pushnotification",
    "version": "1.0.0",
    "description": "A Vue.js project",
    "author": "Roger Camargo <huogerac@gmail.com>",
    "private": true,
    "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
    "test": "npm run unit",
    "lint": "eslint --ext .js,.vue src test/unit/specs"
    },
    "dependencies": {
    "firebase": "^5.0.4",
    "material-design-lite": "^1.3.0",
    "vue": "^2.5.2",
    "vue-resource": "^1.5.1",
    "vue-router": "^3.0.1",
    "vuefire": "^1.4.5",
    "xml-parser": "^1.2.1"
    },
    "devDependencies": {
    "ngrok": "^3.0.1",
    "autoprefixer": "^7.1.5",
    "babel-core": "^6.26.0",
    "babel-eslint": "^8.0.1",
    "babel-loader": "^7.1.2",
    "babel-plugin-istanbul": "^4.1.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-2": "^6.24.1",
    "babel-register": "^6.26.0",
    "chai": "^4.1.2",
    "chalk": "^2.1.0",
    "connect-history-api-fallback": "^1.4.0",
    "copy-webpack-plugin": "^4.1.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "cssnano": "^3.10.0",
    "eslint": "^4.9.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.9.0",
    "eslint-plugin-html": "^3.2.2",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.6.0",
    "eslint-plugin-standard": "^3.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.16.2",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.5",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "http-proxy-middleware": "^0.17.4",
    "inject-loader": "^3.0.1",
    "karma": "^1.7.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-phantomjs-shim": "^1.5.0",
    "karma-sinon-chai": "^1.3.2",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "^2.0.5",
    "mocha": "^4.0.1",
    "opn": "^5.1.0",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.3.0",
    "phantomjs-prebuilt": "^2.1.15",
    "rimraf": "^2.6.2",
    "semver": "^5.4.1",
    "shelljs": "^0.7.8",
    "sinon": "^4.0.1",
    "sinon-chai": "^2.14.0",
    "sw-precache-webpack-plugin": "^0.11.5",
    "uglify-es": "^3.1.3",
    "url-loader": "^0.6.2",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.3",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.7.1",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-middleware": "^1.12.0",
    "webpack-hot-middleware": "^2.19.1",
    "webpack-merge": "^4.1.0"
    },
    "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
    },
    "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
    ]
    }