4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/Account.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import AuthUserContext from "./AuthUserContext";
4 | import { PasswordForgetForm } from "./PasswordForget";
5 | import PasswordChangeForm from "./PasswordChange";
6 | import withAuthorization from "./withAuthorization"; //redirects to sign in if user not signed in
7 |
8 | const AccountPage = () => (
9 | //authUser is passed down via Context API (It is set at withAuthentication.js file)
10 |
11 | {authUser => (
12 |
13 |
14 |
15 | Change/Reset Password for : {authUser.email}
16 |
17 | {/* disabling password changes/resets if user is logged in through facebook */}
18 | {authUser.providerData[0].providerId === "facebook.com" ? null : (
19 |
56 | // );
57 |
58 | const authCondition = authUser => !!authUser;
59 |
60 | export default withAuthorization(authCondition)(HomePage); //grants authorization to open endpoint if an user is signed in
61 |
--------------------------------------------------------------------------------
/src/components/Landing.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const LandingPage = () => (
4 |
5 |
Landing Page
6 |
7 |
This page is public, accessible by everyone
8 |
9 |
10 | Est cillum sunt qui nulla esse mollit quis magna enim non non laborum
11 | culpa nisi. Amet do nisi minim amet dolor quis veniam fugiat exercitation
12 | duis anim occaecat. Mollit pariatur minim aute eiusmod est ad dolore
13 | labore fugiat deserunt quis. Aliquip dolor ex irure sunt voluptate
14 | exercitation voluptate incididunt.
15 |
168 | );
169 | }
170 | }
171 |
172 | //################### Sign Up Link ###################
173 | //used in the sign in when the user don't have an account registered yet
174 | const SignUpLink = () => (
175 |
176 | Don't have an account? Sign Up
177 |
178 | );
179 |
180 | //exports
181 | export default withRouter(SignUpPage); //using a HoC to get access to history
182 | export { SignUpForm, SignUpLink };
183 |
184 | //
220 |
--------------------------------------------------------------------------------
/src/components/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/components/withAuthentication.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { firebase } from "../firebase";
3 |
4 | import AuthUserContext from "./AuthUserContext"; //using provider's context api
5 |
6 | const withAuthentication = Component => {
7 | class WithAuthentication extends React.Component {
8 | state = {
9 | authUser: null
10 | };
11 |
12 | componentDidMount() {
13 | firebase.auth.onAuthStateChanged(authUser => {
14 | authUser
15 | ? this.setState({ authUser })
16 | : this.setState({ authUser: null });
17 | });
18 | }
19 |
20 | render() {
21 | const { authUser } = this.state;
22 | console.log("withAuthentication file authUser", authUser);
23 | return (
24 | // passing down the authUser value, so other components can consume it
25 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | return WithAuthentication;
33 | };
34 |
35 | export default withAuthentication;
36 |
--------------------------------------------------------------------------------
/src/components/withAuthorization.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { withRouter } from "react-router-dom";
3 |
4 | import AuthUserContext from "./AuthUserContext";
5 | import { firebase } from "../firebase";
6 | import * as routes from "../constants/routes";
7 |
8 | const withAuthorization = authCondition => Component => {
9 | class WithAuthorization extends React.Component {
10 | componentDidMount() {
11 | firebase.auth.onAuthStateChanged(authUser => {
12 | if (!authCondition(authUser)) {
13 | //if the authorization fails, redirects to sign in page
14 | this.props.history.push(routes.SIGN_IN);
15 | }
16 | });
17 | }
18 |
19 | render() {
20 | return (
21 |
22 | {/* it either renders the passed component or not */}
23 | {authUser =>
24 | authUser ? (
25 |
26 | ) : null
27 | }
28 |
29 | );
30 | }
31 | }
32 |
33 | return withRouter(WithAuthorization); //using withRouter so we have access to history props
34 | };
35 |
36 | export default withAuthorization;
37 |
--------------------------------------------------------------------------------
/src/constants/routes.js:
--------------------------------------------------------------------------------
1 | export const SIGN_UP = "/signup";
2 | export const SIGN_IN = "/signin";
3 | export const LANDING = "/";
4 | export const HOME = "/home";
5 | export const ACCOUNT = "/account";
6 | export const PASSWORD_FORGET = "/pw-forget";
7 |
--------------------------------------------------------------------------------
/src/firebase/auth.js:
--------------------------------------------------------------------------------
1 | import { auth, facebookProvider } from "./firebase"; //importing the previously instatiated object from the firebase.js config file
2 |
3 | //## below the authentication functions ##
4 |
5 | //sign up
6 | export const doCreateUserWithEmailAndPassword = (email, password) =>
7 | auth.createUserWithEmailAndPassword(email, password);
8 |
9 | //sign in
10 | export const doSignInWithEmailAndPassword = (email, password) =>
11 | auth.signInWithEmailAndPassword(email, password);
12 |
13 | //sign out
14 | export const doSignOut = () => auth.signOut();
15 |
16 | //## below are two more functions, for resetting or changing passwords ##
17 |
18 | //password reset
19 | export const doPasswordReset = email => auth.sendPasswordResetEmail(email);
20 |
21 | //password change
22 | export const doPasswordChange = password =>
23 | auth.currentUser.updatePassword(password);
24 |
25 | //#### for
26 | // facebook #####
27 | export const doFacebookSignIn = () => auth.signInWithPopup(facebookProvider);
28 |
--------------------------------------------------------------------------------
/src/firebase/db.js:
--------------------------------------------------------------------------------
1 | //this is going to store Firebase realtime database API code
2 | import { db } from "./firebase";
3 |
4 | //##########3 user API
5 |
6 | //create an user and store it at users/id path (it's an asynchronous func)
7 | export const doCreateUser = (id, username, email) =>
8 | db.ref(`users/${id}`).set({
9 | username,
10 | email
11 | });
12 |
13 | //returns all users from firebase realtime db
14 | export const onceGetUsers = () => db.ref("users").once("value");
15 |
16 | export const doGetAnUnser = uid => db.ref(`users/${uid}`).once("value");
17 |
18 | // other APIs could come below
19 |
--------------------------------------------------------------------------------
/src/firebase/firebase.js:
--------------------------------------------------------------------------------
1 | import firebase from "firebase/app";
2 | import "firebase/auth";
3 | import "firebase/database";
4 |
5 | //this config is being used for both development and production environment. Though, it is a best practice creating a second project and have two configs: one for production (prodConfig) and another for development (devConfig), so you choose the config based on the environment.
6 |
7 | const config = {
8 | apiKey: "AIzaSyAcOIzZPhgquE2g4NkrJovuIucSkMzYupI",
9 | authDomain: "react-firebase-authentic-b43cd.firebaseapp.com",
10 | databaseURL: "https://react-firebase-authentic-b43cd.firebaseio.com",
11 | projectId: "react-firebase-authentic-b43cd",
12 | storageBucket: "react-firebase-authentic-b43cd.appspot.com",
13 | messagingSenderId: "502482847019"
14 | };
15 |
16 | if (!firebase.apps.length) {
17 | //initializing with the config object
18 | firebase.initializeApp(config);
19 | }
20 |
21 | //separting database API and authentication
22 | const db = firebase.database();
23 | const auth = firebase.auth();
24 |
25 | const facebookProvider = new firebase.auth.FacebookAuthProvider();
26 |
27 | export { db, auth, facebookProvider };
28 |
--------------------------------------------------------------------------------
/src/firebase/index.js:
--------------------------------------------------------------------------------
1 | import * as auth from "./auth"; //all functions is gonna be preceded with auth
2 | import * as db from "./db";
3 | import * as firebase from "./firebase";
4 |
5 | export { auth, db, firebase };
6 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0 auto;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | .div-flex {
12 | display: flex;
13 | justify-content: center;
14 | /* background: black; */
15 | }
16 |
17 | .centered {
18 | margin-top: 20px;
19 | text-align: center;
20 | /* background: black; */
21 | }
22 |
23 | .App-logo {
24 | animation: App-logo-spin infinite 20s linear;
25 | /* height: 20vmin; */
26 | }
27 |
28 | @keyframes App-logo-spin {
29 | from {
30 | transform: rotate(0deg);
31 | }
32 | to {
33 | transform: rotate(360deg);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import "bootstrap/dist/css/bootstrap.min.css";
2 | import React from "react";
3 | import ReactDOM from "react-dom";
4 | import "./index.css";
5 | import App from "./components/App";
6 | import * as serviceWorker from "./serviceWorker";
7 |
8 | ReactDOM.render(, document.getElementById("root"));
9 |
10 | // If you want your app to work offline and load faster, you can change
11 | // unregister() to register() below. Note this comes with some pitfalls.
12 | // Learn more about service workers: http://bit.ly/CRA-PWA
13 | serviceWorker.unregister();
14 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export function register(config) {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Let's check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl, config);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl, config);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl, config) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 |
70 | // Execute callback
71 | if (config.onUpdate) {
72 | config.onUpdate(registration);
73 | }
74 | } else {
75 | // At this point, everything has been precached.
76 | // It's the perfect time to display a
77 | // "Content is cached for offline use." message.
78 | console.log('Content is cached for offline use.');
79 |
80 | // Execute callback
81 | if (config.onSuccess) {
82 | config.onSuccess(registration);
83 | }
84 | }
85 | }
86 | };
87 | };
88 | })
89 | .catch(error => {
90 | console.error('Error during service worker registration:', error);
91 | });
92 | }
93 |
94 | function checkValidServiceWorker(swUrl, config) {
95 | // Check if the service worker can be found. If it can't reload the page.
96 | fetch(swUrl)
97 | .then(response => {
98 | // Ensure service worker exists, and that we really are getting a JS file.
99 | if (
100 | response.status === 404 ||
101 | response.headers.get('content-type').indexOf('javascript') === -1
102 | ) {
103 | // No service worker found. Probably a different app. Reload the page.
104 | navigator.serviceWorker.ready.then(registration => {
105 | registration.unregister().then(() => {
106 | window.location.reload();
107 | });
108 | });
109 | } else {
110 | // Service worker found. Proceed as normal.
111 | registerValidSW(swUrl, config);
112 | }
113 | })
114 | .catch(() => {
115 | console.log(
116 | 'No internet connection found. App is running in offline mode.'
117 | );
118 | });
119 | }
120 |
121 | export function unregister() {
122 | if ('serviceWorker' in navigator) {
123 | navigator.serviceWorker.ready.then(registration => {
124 | registration.unregister();
125 | });
126 | }
127 | }
128 |
--------------------------------------------------------------------------------