diff --git a/server/routes/validate.js b/server/routes/validate.js
index 86327f4..c5820d4 100644
--- a/server/routes/validate.js
+++ b/server/routes/validate.js
@@ -4,16 +4,26 @@ const router = express.Router();
const route = function(db) {
router.post('/', function(req, res, next) {
- const passcode = req.body.passcode;
+ const password = req.body.password;
+ const passwordRef = db.ref('server/password');
+ passwordRef.once('value', function(s) {
+ res.json({
+ valid: password === s.val(),
+ });
+ });
+ });
+
+ router.post('/uid', function(req, res, next) {
+ const password = req.body.password;
const uid = req.body.uid;
- const passcodeRef = db.ref('server/passcode');
- passcodeRef.once('value', function(s) {
+ const passwordRef = db.ref('server/password');
+ passwordRef.once('value', function(s) {
if (!uid) {
return res.status(400).json({
error: 'No UID',
});
}
- const valid = passcode === s.val();
+ const valid = password === s.val();
const userRef = db.ref(`users/${uid}`)
.set({
isAdmin: false,
diff --git a/src/App.js b/src/App.js
index 5852be9..bda87c5 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,11 +1,9 @@
import React, { Component } from 'react';
-import { BrowserRouter, Switch, Route } from 'react-router-dom';
+import { BrowserRouter } from 'react-router-dom';
-import Navigation from './components/Navigation';
-import Home from './routes/Home';
-import Login from './routes/Login';
+import Menu from './components/Menu';
+import Login from './components/Login';
import Admin from './routes/Admin';
-import NotFound from './routes/NotFound';
import { auth, db } from './rebase';
@@ -28,20 +26,21 @@ class App extends Component {
}
componentWillMount() {
- this.registerAuthStateChange('main', (user) => {
- console.log('mainevent', user);
- if (user) {
- this.setState({
- user: {
- uid: user.uid,
- displayName: user.displayName,
- photoURL: user.photoURL,
- },
- });
- this.userStateBinding = db.bindToState(`users/${user.uid}`, {
- context: this,
- state: 'user.data',
- });
+ // Set up auth state observer
+ auth.onAuthStateChanged((res) => {
+ if (res) {
+ const user = {...this.state.user};
+ user.uid = res.uid;
+ user.displayName = res.displayName;
+ user.photoURL = res.photoURL;
+ user.data = {};
+ this.setState({ user });
+ if (!this.userStateBinding) {
+ this.userStateBinding = db.bindToState(`users/${user.uid}`, {
+ context: this,
+ state: 'user.data',
+ });
+ }
} else if (this.userStateBinding) {
db.removeBinding(this.userStateBinding);
this.setState({
@@ -49,38 +48,25 @@ class App extends Component {
});
}
});
-
- // Set up auth state observer
- auth.onAuthStateChanged((user) => {
- // loop through all registered auth state events
- Object.values(this.authStateEvents).forEach((fn) => fn(user));
- });
- }
-
- registerAuthStateChange = (key, fn) => {
- this.authStateEvents[key] = fn;
}
render() {
return (
-
-
-
-
- } />
- } />
- } />
-
-
-
-
+
+
+
+ {this.state.user.uid && this.state.user.data.approved
+ ? ''
+ :
+ }
+ {this.state.user.data.isAdmin
+ ?
+ : ''
+ }
+
+
+
+
);
}
}
diff --git a/src/Colours.js b/src/Colours.js
new file mode 100644
index 0000000..c3668f3
--- /dev/null
+++ b/src/Colours.js
@@ -0,0 +1,8 @@
+const Colours = {
+ nearblack: '#242424',
+ darkgrey: '#2A2B2F',
+ offwhite: '#EFEFEF',
+ white: '#FFFFFF',
+}
+
+export default Colours;
diff --git a/src/components/Login.js b/src/components/Login.js
new file mode 100644
index 0000000..694badf
--- /dev/null
+++ b/src/components/Login.js
@@ -0,0 +1,166 @@
+import React from 'react';
+import { auth } from '../rebase';
+import firebase from 'firebase';
+import axios from 'axios';
+import styled from 'styled-components';
+
+class Login extends React.Component {
+ state = {
+ authProvider: null,
+ password: null,
+ passwordValid: false,
+ }
+
+ componentWillUpdate(prev, next) {
+ const authProvider = next.authProvider;
+ if (!this.props.user.uid && next.passwordValid && authProvider) {
+ const password = this.state.password;
+ if (authProvider === 'anonymous') {
+ auth.signInAnonymously().then(res => {
+ this.submitUid(res.uid, password);
+ }).catch(this.handleError);
+ } else if (authProvider === 'twitter') {
+ const provider = new firebase.auth.TwitterAuthProvider();
+ auth.signInWithPopup(provider).then(res => {
+ this.submitUid(res.user.uid, password);
+ }).catch(this.handleError);
+ } else if (authProvider === 'facebook') {
+ const provider = new firebase.auth.FacebookAuthProvider();
+ provider.addScope('email');
+ auth.signInWithPopup(provider).then(res => {
+ this.submitUid(res.user.uid, password);
+ }).catch(err => console.error(err));
+ }
+ }
+ }
+
+ handleError = (err) => {
+ console.error(err);
+ }
+
+ submitPassword = (e) => {
+ e.preventDefault();
+ const password = this.password.value;
+ if (this.props.user.uid) {
+ return this.submitUid(this.props.user.uid, password);
+ }
+ this.form.reset();
+ axios.post('/api/validate', { password }).then((res) => {
+ if (res.data.valid) {
+ this.setState({
+ password,
+ passwordValid: true,
+ });
+ }
+ }).catch(this.handleError);
+ }
+
+ submitUid = (uid, password) => {
+ if (uid && password) {
+ axios.post('/api/validate/uid', { uid, password }).then(res => {
+ auth.signInWithCustomToken(res.data.token)
+ .catch(this.handleError);
+ }).catch(this.handleError);
+ }
+ }
+/*
+ authWithTwitterUpgrade = () => {
+ const currentUid = this.props.user.uid;
+ const provider = new firebase.auth.TwitterAuthProvider();
+ auth.signInWithPopup(provider).then(res => {
+ const newUid = res.user.uid;
+ if (newUid) {
+ setTimeout(() => {
+ console.log('upgrading', { currentUid, newUid });
+ axios.post('/api/upgrade', {
+ currentUid,
+ newUid,
+ }).then(res => {
+ auth.signInWithCustomToken(res.data.token)
+ .catch((err) => {
+ console.error(err);
+ });
+ }).catch(err => console.error(err));
+ },500);
+ }
+ }).catch(err => console.error(err));
+ }
+*/
+
+ authAnonymously = (e) => {
+ e.preventDefault();
+ this.setState({ authProvider: 'anonymous' });
+ }
+
+ authWithProvider = (authProvider) => {
+ this.setState({ authProvider });
+ }
+
+ renderPasswordInput = () => {
+ return (
+
+
Please enter the password to continue
+
+
+ )
+ }
+
+ renderIntro = () => {
+ return (
+
+
Sign in
+
Sign in anonymously
+
or
+
Sign in with:
+
+
+
+ )
+ }
+
+ render() {
+ const authProvider = this.state.authProvider;
+ const isAuthed = this.props.user.uid !== null;
+ const isApproved = this.props.user.data.approved;
+ const isAnonymous = this.props.user.data.isAnonymous;
+ const isValid = this.state.passwordValid;
+ console.log({ authProvider, isAuthed, isApproved, isAnonymous, isValid });
+
+ let state;
+ if (!isAuthed && !authProvider) {
+ state = 'intro';
+ } else if ((!isAuthed && !isValid) || !isApproved) {
+ state = 'password';
+ }
+ return (
+
+ { state === 'intro' ? this.renderIntro() : '' }
+ { state === 'password' ? this.renderPasswordInput() : '' }
+
+ )
+ }
+}
+
+const LoginContainer = styled.div`
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ padding: 5%;
+ border: 1px solid black;
+ text-align: center;
+`
+const Link = styled.a`
+ text-decoration: none;
+`
+const Input = styled.input`
+ border: 1px solid black;
+`;
+const Button = styled.button`
+ border: 1px solid black;
+`
+
+export default Login;
diff --git a/src/components/Menu.js b/src/components/Menu.js
new file mode 100644
index 0000000..4d25f6f
--- /dev/null
+++ b/src/components/Menu.js
@@ -0,0 +1,133 @@
+import React from 'react';
+import { auth } from '../rebase';
+import styled from 'styled-components';
+import Colours from '../Colours';
+
+class Menu extends React.Component {
+ state = {
+ expanded: false,
+ }
+
+ logout = () => {
+ auth.signOut();
+ }
+
+ toggleMenu = () => {
+ this.setState({ expanded: !this.state.expanded });
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ Log out
+
+ )
+ }
+}
+
+
+const MenuContainer = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 9;
+ opacity: ${props => props.expanded ? '1' : '.6'};
+ min-width: ${props => props.expanded ? '140px' : '50px'};
+ min-height: ${props => props.expanded ? '100%' : '42px'};
+ background-color: ${Colours.darkgrey};
+ overflow: hidden;
+ transition: min-width .5s ease-in-out,
+ min-height .5s ease-in-out,
+ opacity .5s ease-in-out;
+
+ &:hover {
+ opacity: 1;
+ }
+
+ &:after {
+ display: block;
+ content: '';
+ width: 0;
+ height: 0;
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ border-top: ${props => props.expanded ? `0 solid ${Colours.darkgrey}` : `32px solid ${Colours.darkgrey}`};
+ border-right: ${props => props.expanded ? `0 solid ${Colours.white}` : `40px solid ${Colours.white}`};
+ transition: border-top .5s ease,
+ border-right .5s ease;
+ }
+`
+
+const MenuButton = styled.button`
+ position: fixed;
+ top: 10px;
+ left: 10px;
+ width: 30px;
+ height: 22px;
+ z-index: 10;
+ background: none;
+ color: ${Colours.offwhite};
+ border: none;
+ cursor: pointer;
+ transform: rotate(0deg);
+ transition: .5s ease-in-out;
+
+ span {
+ display: block;
+ position: absolute;
+ height: 4px;
+ width: 100%;
+ border-radius: 9px;
+ opacity: 1;
+ left: 0;
+ transform: rotate(0deg);
+ transition: .25s ease-in-out;
+ background-color: ${props => props.expanded ? Colours.offwhite : Colours.white}
+ }
+
+ span:nth-child(1) {
+ top: ${props => props.expanded ? '9px' : '0'};
+ left: ${props => props.expanded ? '50%' : '0'};
+ width: ${props => props.expanded ? '0%' : '100%'};
+ }
+
+ span:nth-child(2) {
+ top: 9px;
+ transform: ${props => props.expanded ? 'rotate(45deg)' : ''};
+ }
+ span:nth-child(3) {
+ top: 9px;
+ transform: ${props => props.expanded ? 'rotate(-45deg)' : ''};
+ }
+
+ span:nth-child(4) {
+ top: ${props => props.expanded ? '9px' : '18px'};
+ left: ${props => props.expanded ? '50%' : '0'};
+ width: ${props => props.expanded ? '0%' : '100%'};
+ }
+`
+
+const LogoutButton = styled.button`
+ display: block;
+ position: absolute;
+ bottom: 0;
+ left: ${props => props.expanded ? '0' : '-100%'};
+ width: 100%;
+ z-index:10;
+ border: 0;
+ padding: 15px 0;
+ background-color: ${Colours.nearblack};
+ color: ${Colours.offwhite};
+ cursor: pointer;
+ transition: left .5s ease-in-out;
+ transition-delay: ${props => props.expanded ? '.75s' : '0s'};
+`
+
+export default Menu;
diff --git a/src/components/Navigation.js b/src/components/Navigation.js
deleted file mode 100644
index af9a070..0000000
--- a/src/components/Navigation.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { Link } from 'react-router-dom';
-
-class Navigation extends React.Component {
- render() {
- return (
-
- )
- }
-}
-
-export default Navigation;
diff --git a/src/routes/Login.js b/src/routes/Login.js
deleted file mode 100644
index 25a58ec..0000000
--- a/src/routes/Login.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import { auth } from '../rebase';
-import firebase from 'firebase';
-import axios from 'axios';
-//import { Redirect } from 'react-router-dom';
-
-class Login extends React.Component {
- authWithTwitter = () => {
- const currentUid = this.props.user.uid;
- const provider = new firebase.auth.TwitterAuthProvider();
- auth.signInWithPopup(provider).then(res => {
- const newUid = res.user.uid;
- if (newUid) {
- setTimeout(() => {
- console.log('upgrading', { currentUid, newUid });
- axios.post('/api/upgrade', {
- currentUid,
- newUid,
- }).then(res => {
- auth.signInWithCustomToken(res.data.token)
- .catch((err) => {
- console.error(err);
- });
- }).catch(err => console.error(err));
- },500);
- }
- }).catch(err => console.error(err));
- }
-
- authWithFacebook = () => {
- if (this.props.user.uid) {
- auth.signOut();
- }
- const provider = new firebase.auth.FacebookAuthProvider();
- provider.addScope('email');
- auth.signInWithPopup(provider).catch(err => console.error(err));
- }
-
- render() {
-// if (this.props.user.uid) {
-// return
-// }
- return (
-
-
Login
-
You need to sign in
-
-
-
Your UID is: {this.props.user.uid}
-
- )
- }
-}
-
-export default Login;