1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-13 10:06:23 +02:00

Firebase is here people!

This commit is contained in:
Kushagra Gour
2018-06-02 10:57:35 +05:30
parent ba9ee64f68
commit 652b0a727d
10 changed files with 343 additions and 5 deletions

View File

@ -28,6 +28,7 @@
}, },
"dependencies": { "dependencies": {
"codemirror": "^5.37.0", "codemirror": "^5.37.0",
"firebase": "^5.0.4",
"preact": "^8.2.6", "preact": "^8.2.6",
"preact-compat": "^3.17.0", "preact-compat": "^3.17.0",
"preact-router": "^2.5.7" "preact-router": "^2.5.7"

49
webmaker/src/analytics.js Normal file
View File

@ -0,0 +1,49 @@
import {
log
} from "./utils";
/* global ga */
// eslint-disable-next-line max-params
export function trackEvent(category, action, label, value) {
if (window.DEBUG) {
log('trackevent', category, action, label, value);
return;
}
if (window.ga) {
ga('send', 'event', category, action, label, value);
}
};
// if online, load after sometime
if (navigator.onLine && !window.DEBUG) {
/* eslint-disable */
// prettier-ignore
setTimeout(function () {
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
if (location.href.indexOf('chrome-extension://') === -1) {
ga('create', 'UA-87786708-1');
} else {
ga('create', 'UA-87786708-1', {
'cookieDomain': 'none'
});
// required for chrome extension protocol
ga('set', 'checkProtocolTask', function () { /* nothing */ });
}
ga('send', 'pageview');
}, 100);
/* eslint-enable */
}

43
webmaker/src/auth.js Normal file
View File

@ -0,0 +1,43 @@
import {
trackEvent
} from './analytics';
import firebase from 'firebase/app'
export const auth = {
logout() {
firebase.auth().signOut();
},
login(providerName) {
var provider;
if (providerName === 'facebook') {
provider = new firebase.auth.FacebookAuthProvider();
} else if (providerName === 'twitter') {
provider = new firebase.auth.TwitterAuthProvider();
} else if (providerName === 'google') {
provider = new firebase.auth.GoogleAuthProvider();
provider.addScope('https://www.googleapis.com/auth/userinfo.profile');
} else {
provider = new firebase.auth.GithubAuthProvider();
}
return firebase
.auth()
.signInWithPopup(provider)
.then(function () {
trackEvent('fn', 'loggedIn', providerName);
// Save to recommend next time
window.db.local.set({
lastAuthProvider: providerName
});
})
.catch(function (error) {
utils.log(error);
if (error.code === 'auth/account-exists-with-different-credential') {
alert(
'You have already signed up with the same email using different social login'
);
}
});
}
}

View File

@ -0,0 +1,74 @@
import { h, Component } from 'preact';
import { jsLibs, cssLibs } from '../libraryList';
import { trackEvent } from '../analytics';
import { auth } from '../auth';
export default class Login extends Component {
login(e) {
const provider = e.target.dataset.authProvider;
trackEvent('ui', 'loginProviderClick', provider);
auth.login(provider);
}
logout(e) {
if (this.unsavedEditCount) {
var shouldDiscard = confirm(
'You have unsaved changes. Do you still want to logout?'
);
if (!shouldDiscard) {
return;
}
}
trackEvent('fn', 'loggedOut');
auth.logout();
}
render() {
return (
<div>
<h2>Login / Signup</h2>
<div>
<p>
<button
type="button"
onClick={this.login.bind(this)}
class="social-login-btn social-login-btn--github btn btn-icon btn--big full-width hint--right hint--always"
data-auth-provider="github"
data-hint="You logged in with Github last time"
>
<svg>
<use xlinkHref="#github-icon" />
</svg>Login with Github
</button>
</p>
<p>
<button
type="button"
onClick={this.login.bind(this)}
class="social-login-btn social-login-btn--google btn btn-icon btn--big full-width hint--right hint--always"
data-auth-provider="google"
data-hint="You logged in with Google last time"
>
<svg>
<use xlinkHref="#google-icon" />
</svg>Login with Google
</button>
</p>
<p class="mb-2">
<button
type="button"
onClick={this.login.bind(this)}
class="social-login-btn social-login-btn--facebook btn btn-icon btn--big full-width hint--right hint--always"
data-auth-provider="facebook"
data-hint="You logged in with Facebook last time"
>
<svg>
<use xlinkHref="#fb-icon" />
</svg>Login with Facebook
</button>
</p>
<p>Join a community of 50,000+ Developers</p>
</div>
</div>
);
}
}

View File

@ -94,7 +94,7 @@ export default class Header extends Component {
Open Open
</a> </a>
<a <a
d-open-modal="loginModal" onClick={this.props.loginBtnHandler}
data-event-category="ui" data-event-category="ui"
data-event-action="loginButtonClick" data-event-action="loginButtonClick"
class="hide-on-login flex flex-v-center hint--rounded hint--bottom-left" class="hide-on-login flex flex-v-center hint--rounded hint--bottom-left"
@ -103,7 +103,7 @@ export default class Header extends Component {
Login/Signup Login/Signup
</a> </a>
<a <a
d-open-modal="profileModal" onClick={this.props.profileBtnHandler}
data-event-category="ui" data-event-category="ui"
data-event-action="headerAvatarClick" data-event-action="headerAvatarClick"
aria-label="See profile or Logout" aria-label="See profile or Logout"
@ -112,7 +112,11 @@ export default class Header extends Component {
<img <img
id="headerAvatarImg" id="headerAvatarImg"
width="20" width="20"
src="" src={
this.props.user
? this.props.user.photoURL || DEFAULT_PROFILE_IMG
: ''
}
class="main-header__avatar-img" class="main-header__avatar-img"
/> />
</a> </a>

View File

@ -0,0 +1,35 @@
import { h, Component } from 'preact';
export default class Profile extends Component {
render() {
return (
<div class="tac">
<img
height="80"
class="profile-modal__avatar-img"
src={
this.props.user
? this.props.user.photoURL || DEFAULT_PROFILE_IMG
: ''
}
id="profileAvatarImg"
alt="Profile image"
/>
<h3 id="profileUserName" class="mb-2">
{this.props.user && this.props.user.displayName
? this.props.user.displayName
: 'Anonymous Creator'}
</h3>
<p>
<button
class="btn"
aria-label="Logout from your account"
onClick={this.props.logoutBtnHandler}
>
Logout
</button>
</p>
</div>
);
}
}

View File

@ -8,6 +8,7 @@ import SavedItemPane from './SavedItemPane.jsx';
import AddLibrary from './AddLibrary.jsx'; import AddLibrary from './AddLibrary.jsx';
import Modal from './Modal.jsx'; import Modal from './Modal.jsx';
import HelpModal from './HelpModal.jsx'; import HelpModal from './HelpModal.jsx';
import Login from './Login.jsx';
import { log, generateRandomId } from '../utils'; import { log, generateRandomId } from '../utils';
import { itemService } from '../itemService'; import { itemService } from '../itemService';
import '../db'; import '../db';
@ -17,6 +18,9 @@ import { modes, cssModes } from '../codeModes';
import { trackEvent } from '../analytics'; import { trackEvent } from '../analytics';
import { deferred } from '../deferred'; import { deferred } from '../deferred';
import { alertsService } from '../notifications'; import { alertsService } from '../notifications';
import firebase from 'firebase/app';
import 'firebase/auth';
import Profile from './Profile';
if (module.hot) { if (module.hot) {
require('preact/debug'); require('preact/debug');
@ -38,6 +42,8 @@ export default class App extends Component {
isAddLibraryModalOpen: false, isAddLibraryModalOpen: false,
isHelpModalOpen: false, isHelpModalOpen: false,
isNotificationsModalOpen: false, isNotificationsModalOpen: false,
isLoginModalOpen: false,
isProfileModalOpen: false,
prefs: {}, prefs: {},
currentItem: { currentItem: {
title: '', title: '',
@ -68,6 +74,45 @@ export default class App extends Component {
infiniteLoopTimeout: 1000 infiniteLoopTimeout: 1000
}; };
this.prefs = {}; this.prefs = {};
firebase.auth().onAuthStateChanged(user => {
this.setState({ isLoginModalOpen: false });
if (user) {
log('You are -> ', user);
alertsService.add('You are now logged in!');
this.setState({ user });
window.user = user;
if (
!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS] &&
window.oldSavedCreationsCountEl
) {
this.fetchItems(false, true).then(items => {
if (!items.length) {
return;
}
this.oldSavedItems = items;
// window.oldSavedCreationsCountEl.textContent = items.length;
this.setState({
isAskToImportModalOpen: true
});
trackEvent('ui', 'askToImportModalSeen');
});
}
window.db.getUser(user.uid).then(customUser => {
if (customUser) {
const prefs = { ...this.state.prefs };
Object.assign(prefs, user.settings);
this.setState({ prefs: prefs });
this.updateSetting();
}
});
} else {
this.setState({ user: undefined });
delete window.user;
// User is signed out.
}
this.updateProfileUi();
});
} }
componentWillMount() { componentWillMount() {
@ -121,6 +166,14 @@ export default class App extends Component {
this.updateSetting(); this.updateSetting();
}); });
} }
updateProfileUi() {
if (this.state.user) {
document.body.classList.add('is-logged-in');
} else {
document.body.classList.remove('is-logged-in');
}
}
refreshEditor() {} refreshEditor() {}
createNewItem() { createNewItem() {
var d = new Date(); var d = new Date();
@ -561,6 +614,27 @@ export default class App extends Component {
} }
autoSaveLoop() {} autoSaveLoop() {}
loginBtnClickHandler() {
this.setState({ isLoginModalOpen: true });
}
profileBtnClickHandler() {
this.setState({ isProfileModalOpen: true });
}
logout(e) {
e.preventDefault();
if (unsavedEditCount) {
var shouldDiscard = confirm(
'You have unsaved changes. Do you still want to logout?'
);
if (!shouldDiscard) {
return;
}
}
trackEvent('fn', 'loggedOut');
window.logout();
}
render() { render() {
return ( return (
<div> <div>
@ -569,10 +643,13 @@ export default class App extends Component {
externalLibCount={this.state.externalLibCount} externalLibCount={this.state.externalLibCount}
openBtnHandler={this.openSavedItemsPane.bind(this)} openBtnHandler={this.openSavedItemsPane.bind(this)}
saveBtnHandler={this.saveBtnClickHandler.bind(this)} saveBtnHandler={this.saveBtnClickHandler.bind(this)}
loginBtnHandler={this.loginBtnClickHandler.bind(this)}
profileBtnHandler={this.profileBtnClickHandler.bind(this)}
addLibraryBtnHandler={this.openAddLibrary.bind(this)} addLibraryBtnHandler={this.openAddLibrary.bind(this)}
isFetchingItems={this.state.isFetchingItems} isFetchingItems={this.state.isFetchingItems}
isSaving={this.state.isSaving} isSaving={this.state.isSaving}
titleInputBlurHandler={this.titleInputBlurHandler.bind(this)} titleInputBlurHandler={this.titleInputBlurHandler.bind(this)}
user={this.state.user}
/> />
<ContentWrap <ContentWrap
currentItem={this.state.currentItem} currentItem={this.state.currentItem}
@ -647,6 +724,18 @@ export default class App extends Component {
onChange={this.updateSetting.bind(this)} onChange={this.updateSetting.bind(this)}
/> />
</Modal> </Modal>
<Modal
show={this.state.isLoginModalOpen}
closeHandler={() => this.setState({ isLoginModalOpen: false })}
>
<Login />
</Modal>
<Modal
show={this.state.isProfileModalOpen}
closeHandler={() => this.setState({ isProfileModalOpen: false })}
>
<Profile user={this.state.user} />
</Modal>
<HelpModal <HelpModal
show={this.state.isHelpModalOpen} show={this.state.isHelpModalOpen}
closeHandler={() => this.setState({ isHelpModalOpen: false })} closeHandler={() => this.setState({ isHelpModalOpen: false })}

View File

@ -1,6 +1,14 @@
import './firebaseInit';
import firebase from 'firebase/app';
import 'firebase/firestore';
import { import {
deferred deferred
} from './deferred' } from './deferred';
import {
trackEvent
} from './analytics';
(() => { (() => {
const FAUX_DELAY = 1; const FAUX_DELAY = 1;
@ -53,6 +61,10 @@ import {
.then(function () { .then(function () {
// Initialize Cloud Firestore through firebase // Initialize Cloud Firestore through firebase
db = firebase.firestore(); db = firebase.firestore();
// const settings = {
// timestampsInSnapshots: true
// };
// db.settings(settings);
utils.log('firebase db ready', db); utils.log('firebase db ready', db);
resolve(db); resolve(db);
}) })
@ -64,7 +76,7 @@ import {
alert( alert(
"Opening Web Maker web app in multiple tabs isn't supported at present and it seems like you already have it opened in another tab. Please use in one tab." "Opening Web Maker web app in multiple tabs isn't supported at present and it seems like you already have it opened in another tab. Please use in one tab."
); );
window.trackEvent('fn', 'multiTabError'); trackEvent('fn', 'multiTabError');
} else if (err.code === 'unimplemented') { } else if (err.code === 'unimplemented') {
// The current browser does not support all of the // The current browser does not support all of the
// features required to enable persistence // features required to enable persistence

View File

@ -0,0 +1,11 @@
import firebase from 'firebase/app';
// import 'firebase/firestore';
const config = {
apiKey: 'AIzaSyBl8Dz7ZOE7aP75mipYl2zKdLSRzBU2fFc',
authDomain: 'web-maker-app.firebaseapp.com',
databaseURL: 'https://web-maker-app.firebaseio.com',
projectId: 'web-maker-app',
storageBucket: 'web-maker-app.appspot.com',
messagingSenderId: '560473480645'
};
firebase.initializeApp(config);

View File

@ -0,0 +1,20 @@
var hideTimeout;
function addNotification(msg) {
const noticationContainerEL = $('#js-alerts-container');
// var n = document.createElement('div');
// div.textContent = msg;
// noticationContainerEL.appendChild(n);
noticationContainerEL.textContent = msg;
noticationContainerEL.classList.add('is-active');
clearTimeout(hideTimeout);
hideTimeout = setTimeout(function () {
noticationContainerEL.classList.remove('is-active');
}, 2000);
}
export const alertsService = {
add: addNotification
};