diff --git a/.gitignore b/.gitignore index 13c5506..39468bd 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ yarn-error.log* .firebase .firebaserc +.idea diff --git a/package-lock.json b/package-lock.json index be3fda3..195ea62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-firebase-authentication", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1012,6 +1012,15 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@semantic-ui-react/event-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.0.1.tgz", + "integrity": "sha512-9YNRr0z9GEvk/yvIzAzv0sbYa/FPrtWTYibu+chJ0CEMQjYDjUdRSqtxXOvP0eM6kZjD1G/Oy1LhPiHG7DRHsg==", + "requires": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + } + }, "@svgr/core": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@svgr/core/-/core-2.4.1.tgz", @@ -2912,6 +2921,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", @@ -3592,6 +3606,11 @@ "whatwg-url": "^7.0.0" } }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -4552,6 +4571,11 @@ } } }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -8624,6 +8648,11 @@ "topo": "2.x.x" } }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, "js-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz", @@ -8761,6 +8790,11 @@ "array-includes": "^3.0.3" } }, + "keyboard-key": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.0.2.tgz", + "integrity": "sha512-05cjQmw4ss/YuY2utmVim0wywDyBZGUivo8siLPkWinwGWtKlO8/4RGbPUqNycwlD3u/3D15eNRjnNAyaTDs8g==" + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -13349,6 +13383,43 @@ "node-forge": "0.7.5" } }, + "semantic-ui-css": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/semantic-ui-css/-/semantic-ui-css-2.4.1.tgz", + "integrity": "sha512-Pkp0p9oWOxlH0kODx7qFpIRYpK1T4WJOO4lNnpNPOoWKCrYsfHqYSKgk5fHfQtnWnsAKy7nLJMW02bgDWWFZFg==", + "requires": { + "jquery": "x.*" + } + }, + "semantic-ui-react": { + "version": "0.83.0", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-0.83.0.tgz", + "integrity": "sha512-rPW4TZwbDJRJZeKxCpYuNiRnBwUpWeDkZ/yF3j5iLNS8hZ6yOjoFFmqGohqpqKD+jVyzlxz2NCmah54mwbNGOw==", + "requires": { + "@babel/runtime": "^7.1.2", + "@semantic-ui-react/event-stack": "^3.0.0", + "classnames": "^2.2.6", + "keyboard-key": "^1.0.2", + "lodash": "^4.17.10", + "prop-types": "^15.6.2", + "shallowequal": "^1.1.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.2.0.tgz", + "integrity": "sha512-oouEibCbHMVdZSDlJBO6bZmID/zA/G/Qx3H1d3rSNPTD+L8UNKvCat7aKWSJ74zYbm5zWGh0GQN0hKj8zYFTCg==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -13510,6 +13581,11 @@ } } }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", diff --git a/package.json b/package.json index 0462ad1..c726912 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,17 @@ { - "name": "react-semantic-ui-firebase-authentication", + "name": "react-firebase-authentication", "version": "0.2.0", "private": true, "dependencies": { + "date-fns": "^1.30.1", "firebase": "^5.6.0", "react": "^16.6.3", "react-dom": "^16.6.3", "react-router-dom": "^4.3.1", "react-scripts": "2.1.1", - "recompose": "^0.30.0" + "recompose": "^0.30.0", + "semantic-ui-css": "^2.4.1", + "semantic-ui-react": "^0.83.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/components/Account/index.js b/src/components/Account/index.js index 9963006..36ec8fb 100644 --- a/src/components/Account/index.js +++ b/src/components/Account/index.js @@ -10,6 +10,8 @@ import { withFirebase } from '../Firebase'; import { PasswordForgetForm } from '../PasswordForget'; import PasswordChangeForm from '../PasswordChange'; +import {Grid, Card, Header, Message, Form, Button } from 'semantic-ui-react' + const SIGN_IN_METHODS = [ { id: 'password', @@ -33,9 +35,29 @@ const AccountPage = () => ( {authUser => (
-

Account: {authUser.email}

- - +
Account: {authUser.email}
+ + + + + Reset Password + + + + + + + + + + New Password + + + + + + +
)} @@ -95,40 +117,51 @@ class LoginManagementBase extends Component { const { activeSignInMethods, error } = this.state; return ( -
- Sign In Methods: - - {error && error.message} -
+ + + Sign In Methods + + {error && +

{error.message}

+
} +
+ {SIGN_IN_METHODS.map(signInMethod => { + const onlyOneLeft = activeSignInMethods.length === 1; + const isEnabled = activeSignInMethods.includes( + signInMethod.id, + ); + + return ( + + {signInMethod.id === 'password' ? ( + + + +
+
+
+ ) : ( + + )} +
+ ); + })} +
+
+
+
); } } @@ -141,20 +174,22 @@ const SocialLoginToggle = ({ onUnlink, }) => isEnabled ? ( - + ) : ( - + ); class DefaultLoginToggle extends Component { @@ -189,34 +224,40 @@ class DefaultLoginToggle extends Component { passwordOne !== passwordTwo || passwordOne === ''; return isEnabled ? ( - + + +
+
) : ( -
- - - - -
+ + ); } } diff --git a/src/components/Admin/index.js b/src/components/Admin/index.js index cd0c7b6..695a4d6 100644 --- a/src/components/Admin/index.js +++ b/src/components/Admin/index.js @@ -7,9 +7,11 @@ import { UserList, UserItem } from '../Users'; import * as ROLES from '../../constants/roles'; import * as ROUTES from '../../constants/routes'; +import { Header } from 'semantic-ui-react'; + const AdminPage = () => (
-

Admin

+
Admin

The Admin Page is accessible by every signed in admin user.

diff --git a/src/components/App/index.js b/src/components/App/index.js index 21e5419..bda7e9b 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -13,12 +13,13 @@ import AdminPage from '../Admin'; import * as ROUTES from '../../constants/routes'; import { withAuthentication } from '../Session'; +import { Container } from 'semantic-ui-react' + const App = () => (
- -
+ @@ -30,6 +31,7 @@ const App = () => ( +
); diff --git a/src/components/Messages/MessageItem.js b/src/components/Messages/MessageItem.js index 78a9bb2..6d994f9 100644 --- a/src/components/Messages/MessageItem.js +++ b/src/components/Messages/MessageItem.js @@ -1,4 +1,12 @@ -import React, { Component } from 'react'; +import React, {Component} from 'react'; +import { distanceInWordsToNow } from 'date-fns' +import { Link } from 'react-router-dom'; +import { Feed, Icon, Form } from 'semantic-ui-react'; + +export const TimeAgo = ({ time }) => ( + +) + class MessageItem extends Component { constructor(props) { @@ -18,54 +26,60 @@ class MessageItem extends Component { }; onChangeEditText = event => { - this.setState({ editText: event.target.value }); + this.setState({editText: event.target.value}); }; onSaveEditText = () => { this.props.onEditMessage(this.props.message, this.state.editText); - this.setState({ editMode: false }); + this.setState({editMode: false}); }; render() { - const { message, onRemoveMessage } = this.props; - const { editMode, editText } = this.state; + const {message, onRemoveMessage} = this.props; + const {editMode, editText} = this.state; return ( -
  • - {editMode ? ( - - ) : ( - - - {message.user.username || message.user.userId} - {' '} - {message.text} {message.editedAt && (Edited)} - - )} - - {editMode ? ( - - - - - ) : ( - - )} + + + + {message.user.username || message.user.userId} + + + + {editMode ? ( +
    + + + +
    + ) : ( + + {message.text} {message.editedAt && (Edited)} + + )} +
    + + {editMode ? ( + + + + + ) : null} - {!editMode && ( - - )} -
  • + {!editMode && ( + + + onRemoveMessage(message.uid)} /> + + )} + + + ); } } diff --git a/src/components/Messages/MessageList.js b/src/components/Messages/MessageList.js index 4e0c49b..47da90a 100644 --- a/src/components/Messages/MessageList.js +++ b/src/components/Messages/MessageList.js @@ -2,12 +2,14 @@ import React from 'react'; import MessageItem from './MessageItem'; +import { Feed } from 'semantic-ui-react' + const MessageList = ({ messages, onEditMessage, onRemoveMessage, }) => ( -
      + {messages.map(message => ( ))} -
    + ); export default MessageList; diff --git a/src/components/Messages/Messages.js b/src/components/Messages/Messages.js index e6e70fd..4a5353e 100644 --- a/src/components/Messages/Messages.js +++ b/src/components/Messages/Messages.js @@ -4,6 +4,8 @@ import { AuthUserContext } from '../Session'; import { withFirebase } from '../Firebase'; import MessageList from './MessageList'; +import { Card, Message, Button, Loader, Form, Icon } from 'semantic-ui-react' + class Messages extends Component { constructor(props) { super(props); @@ -88,47 +90,40 @@ class Messages extends Component { render() { const { users } = this.props; const { text, messages, loading } = this.state; - return ( {authUser => ( -
    - {!loading && messages && ( - - )} - - {loading &&
    Loading ...
    } - - {messages && ( - ({ - ...message, - user: users - ? users[message.userId] - : { userId: message.userId }, - }))} - onEditMessage={this.onEditMessage} - onRemoveMessage={this.onRemoveMessage} - /> - )} - - {!messages &&
    There are no messages ...
    } - -
    - this.onCreateMessage(event, authUser) - } - > - - -
    -
    + + + + {loading && } + + {!loading && messages && ( + + )} + + {messages && ( ({ + ...message, + user: users + ? users[message.userId] + : { userId: message.userId }, + }))} + onEditMessage={this.onEditMessage} + onRemoveMessage={this.onRemoveMessage} + />)} + + {!loading && !messages && +

    There are no messages ...

    +
    } + + {!loading &&
    this.onCreateMessage(event, authUser)}> + + + } +
    +
    +
    )}
    ); diff --git a/src/components/Navigation/index.js b/src/components/Navigation/index.js index 156e27a..2be5ebd 100644 --- a/src/components/Navigation/index.js +++ b/src/components/Navigation/index.js @@ -6,6 +6,8 @@ import SignOutButton from '../SignOut'; import * as ROUTES from '../../constants/routes'; import * as ROLES from '../../constants/roles'; +import { Container, Menu } from 'semantic-ui-react' + const Navigation = () => ( {authUser => @@ -19,36 +21,52 @@ const Navigation = () => ( ); const NavigationAuth = ({ authUser }) => ( -
      -
    • - Landing -
    • -
    • - Home -
    • -
    • - Account -
    • - {authUser.roles.includes(ROLES.ADMIN) && ( -
    • - Admin -
    • - )} -
    • + + + + + + {authUser.roles.includes(ROLES.ADMIN) && ( + + )} -
    • -
    + + ); const NavigationNonAuth = () => ( -
      -
    • - Landing -
    • -
    • - Sign In -
    • -
    + + + + + + + + ); export default Navigation; diff --git a/src/components/PasswordChange/index.js b/src/components/PasswordChange/index.js index 14fa581..a1e7543 100644 --- a/src/components/PasswordChange/index.js +++ b/src/components/PasswordChange/index.js @@ -2,6 +2,8 @@ import React, { Component } from 'react'; import { withFirebase } from '../Firebase'; +import { Form, Message, Button } from 'semantic-ui-react' + const INITIAL_STATE = { passwordOne: '', passwordTwo: '', @@ -41,27 +43,36 @@ class PasswordChangeForm extends Component { passwordOne !== passwordTwo || passwordOne === ''; return ( -
    - - - - - {error &&

    {error.message}

    } -
    + + ); } } diff --git a/src/components/PasswordForget/index.js b/src/components/PasswordForget/index.js index 9d6fa38..ec96d60 100644 --- a/src/components/PasswordForget/index.js +++ b/src/components/PasswordForget/index.js @@ -4,11 +4,15 @@ import { Link } from 'react-router-dom'; import { withFirebase } from '../Firebase'; import * as ROUTES from '../../constants/routes'; +import {Grid, Form, Header, Button, Message} from 'semantic-ui-react' + const PasswordForgetPage = () => ( -
    -

    PasswordForget

    - -
    + + +
    Password Forget
    + +
    +
    ); const INITIAL_STATE = { @@ -48,28 +52,32 @@ class PasswordForgetFormBase extends Component { const isInvalid = email === ''; return ( -
    - - - - {error &&

    {error.message}

    } -
    +
    + {error && +

    {error.message}

    +
    } +
    + + + + + +
    +
    ); } } const PasswordForgetLink = () => ( -

    - Forgot Password? -

    + Forgot Password? ); export default PasswordForgetPage; diff --git a/src/components/SignIn/index.js b/src/components/SignIn/index.js index 91e3f56..c2dc32f 100644 --- a/src/components/SignIn/index.js +++ b/src/components/SignIn/index.js @@ -7,16 +7,19 @@ import { PasswordForgetLink } from '../PasswordForget'; import { withFirebase } from '../Firebase'; import * as ROUTES from '../../constants/routes'; +import { Grid, Form, Button, Header, Icon, Message, Divider } from 'semantic-ui-react'; + const SignInPage = () => ( -
    -

    SignIn

    - - - - - - -
    + + +
    Sign In
    + + + + + +
    +
    ); const INITIAL_STATE = { @@ -68,27 +71,36 @@ class SignInFormBase extends Component { const isInvalid = password === '' || email === ''; return ( -
    - - - - - {error &&

    {error.message}

    } -
    +
    + {error && +

    {error.message}

    +
    } +
    + + + + + + + + + + + Or sign in with + +
    ); } } @@ -130,10 +142,14 @@ class SignInGoogleBase extends Component { const { error } = this.state; return ( -
    - - - {error &&

    {error.message}

    } + + + + {error && +

    {error.message}

    +
    }
    ); } @@ -176,10 +192,14 @@ class SignInFacebookBase extends Component { const { error } = this.state; return ( -
    - - - {error &&

    {error.message}

    } + + + + {error && +

    {error.message}

    +
    }
    ); } @@ -222,10 +242,14 @@ class SignInTwitterBase extends Component { const { error } = this.state; return ( -
    - - - {error &&

    {error.message}

    } + + + + {error && +

    {error.message}

    +
    }
    ); } diff --git a/src/components/SignOut/index.js b/src/components/SignOut/index.js index cfee4ed..b54a73e 100644 --- a/src/components/SignOut/index.js +++ b/src/components/SignOut/index.js @@ -2,10 +2,15 @@ import React from 'react'; import { withFirebase } from '../Firebase'; +import { Menu } from 'semantic-ui-react' + const SignOutButton = ({ firebase }) => ( - + + + ); export default withFirebase(SignOutButton); diff --git a/src/components/SignUp/index.js b/src/components/SignUp/index.js index f10e50b..b27d0b2 100644 --- a/src/components/SignUp/index.js +++ b/src/components/SignUp/index.js @@ -4,12 +4,15 @@ import { Link, withRouter } from 'react-router-dom'; import { withFirebase } from '../Firebase'; import * as ROUTES from '../../constants/routes'; import * as ROLES from '../../constants/roles'; +import {Form, Button, Grid, Header, Message, Checkbox } from 'semantic-ui-react'; const SignUpPage = () => ( -
    -

    SignUp

    - -
    + + +
    Sign Up
    + +
    +
    ); const INITIAL_STATE = { @@ -78,8 +81,8 @@ class SignUpFormBase extends Component { this.setState({ [event.target.name]: event.target.value }); }; - onChangeCheckbox = event => { - this.setState({ [event.target.name]: event.target.checked }); + onChangeCheckbox = () => { + this.setState({ isAdmin: !this.state.isAdmin }); }; render() { @@ -99,50 +102,59 @@ class SignUpFormBase extends Component { username === ''; return ( -
    - - - - - - - - {error &&

    {error.message}

    } -
    +
    + {error && +

    {error.message}

    +
    } +
    + + + + + + + + + + + + + + + + + + + + + + +
    +
    ); } } diff --git a/src/components/Users/UserItem.js b/src/components/Users/UserItem.js index 05e4319..5e4118f 100644 --- a/src/components/Users/UserItem.js +++ b/src/components/Users/UserItem.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { withFirebase } from '../Firebase'; +import { Card, Loader, Button } from 'semantic-ui-react'; class UserItem extends Component { constructor(props) { @@ -42,32 +43,31 @@ class UserItem extends Component { const { user, loading } = this.state; return ( -
    -

    User ({this.props.match.params.id})

    - {loading &&
    Loading ...
    } - - {user && ( -
    - - ID: {user.uid} - - - E-Mail: {user.email} - - - Username: {user.username} - - - - -
    - )} -
    + + {loading ? : + User: {user.uid} + + {user && ( +
    + + + Username: {user.username} + + {user.email} +
    + +
    +
    + )} +
    +
    } +
    ); } } diff --git a/src/components/Users/UserList.js b/src/components/Users/UserList.js index 85b4955..6062f01 100644 --- a/src/components/Users/UserList.js +++ b/src/components/Users/UserList.js @@ -4,6 +4,8 @@ import { Link } from 'react-router-dom'; import { withFirebase } from '../Firebase'; import * as ROUTES from '../../constants/routes'; +import { Header, Loader, Table, Button } from 'semantic-ui-react' + class UserList extends Component { constructor(props) { super(props); @@ -41,33 +43,32 @@ class UserList extends Component { return (
    -

    Users

    - {loading &&
    Loading ...
    } -
      - {users.map(user => ( -
    • - - ID: {user.uid} - - - E-Mail: {user.email} - - - Username: {user.username} - - - Users + {loading ? : + + + ID + Username + Email Address + Actions + + + + {users.map((user, i) => ( + + {user.uid} + {user.username} + {user.email} + + + + + ))} + +
      }
    ); } diff --git a/src/index.css b/src/index.css index cee5f34..d631847 100644 --- a/src/index.css +++ b/src/index.css @@ -12,3 +12,7 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } + +.inline { + display: inline-block; +} diff --git a/src/index.js b/src/index.js index 5275a6b..aab58de 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; - +import 'semantic-ui-css/semantic.min.css'; import './index.css'; import * as serviceWorker from './serviceWorker';