82 | This is an introduction screen that shows up after the user
83 | successfully logs in for the first time. It's a good opportunity to
84 | collect additional information or provide them with important details
85 | about how your application works.
86 |
115 | So this is your dashboard. Maybe you'll put a few graphs here, you've
116 | always wanted to try out D3. Maybe a news feed, or updates on new
117 | features.
118 |
119 |
120 | So this is your dashboard. Maybe you'll put a few graphs here, you've
121 | always wanted to try out D3. Maybe a news feed, or updates on new
122 | features. So this is your dashboard. Maybe you'll put a few graphs
123 | here, you've always wanted to try out D3. Maybe a news feed, or
124 | updates on new features. So this is your dashboard. Maybe you'll put a
125 | few graphs here, you've always wanted to try out D3. Maybe a news
126 | feed, or updates on new features.
127 |
128 |
129 | So this is your dashboard. Maybe you'll put a few graphs here, you've
130 | always wanted to try out D3. Maybe a news feed, or updates on new
131 | features.
132 |
133 |
134 | So this is your dashboard. Maybe you'll put a few graphs here, you've
135 | always wanted to try out D3. Maybe a news feed, or updates on new
136 | features. So this is your dashboard. Maybe you'll put a few graphs
137 | here, you've always wanted to try out D3. Maybe a news feed, or
138 | updates on new features.
139 |
140 |
141 | So this is your dashboard. Maybe you'll put a few graphs here, you've
142 | always wanted to try out D3. Maybe a news feed, or updates on new
143 | features.
144 |
145 |
146 | So this is your dashboard. Maybe you'll put a few graphs here, you've
147 | always wanted to try out D3. Maybe a news feed, or updates on new
148 | features. So this is your dashboard. Maybe you'll put a few graphs
149 | here, you've always wanted to try out D3. Maybe a news feed, or
150 | updates on new features.
151 |
152 |
153 | So this is your dashboard. Maybe you'll put a few graphs here, you've
154 | always wanted to try out D3. Maybe a news feed, or updates on new
155 | features.
156 |
14 | A fully-featured single-page app template, hosted and running in
15 | minutes. Based on Create-React-App and Firebase. Written with
16 | React-Hooks.
17 |
18 |
19 |
20 | Modern authentication and onboarding UI flows have already been built
21 | out, it's as simple as plugging in your Firebase API keys.
22 |
23 |
Mobile-ready responsive design.
24 |
25 | Utilizes Styled-Components, carefully using global variables that
26 | allow you to quickly and easily adjust to your tastes.
27 |
28 |
29 | It's built entirely with React Hooks and the new Context API. Built on
30 | top of Create-React-App.
31 |
32 |
33 | Requires very few dependencies. The least popular module it uses has
34 | 6.4k stars on Github.
35 |
36 |
37 | Basic security rules have already been written for the Firestore DB.
38 |
39 |
40 | Push Notifications set up out of the box, with a cloud function
41 | supplied for triggering messages.
42 |
28 | By accessing this web site, you are agreeing to be bound by these web
29 | site Terms and Conditions of Use, applicable laws and regulations and
30 | their compliance. If you disagree with any of the stated terms and
31 | conditions, you are prohibited from using or accessing this site. The
32 | materials contained in this site are secured by relevant copyright and
33 | trade mark law.
34 |
35 |
2. Use License
36 |
37 |
38 | Permission is allowed to temporarily download one duplicate of the
39 | materials (data or programming) on react-firebase-essentials.com's
40 | site for individual and non-business use only. This is the just a
41 | permit of license and not an exchange of title, and under this permit
42 | you may not:
43 |
44 |
modify or copy the materials;
45 |
46 | use the materials for any commercial use , or for any public
47 | presentation (business or non-business);{" "}
48 |
49 |
50 | attempt to decompile or rebuild any product or material contained
51 | on react-firebase-essentials.com's site;
52 |
53 |
54 | remove any copyright or other restrictive documentations from the
55 | materials; or
56 |
57 |
58 | transfer the materials to someone else or even "mirror" the
59 | materials on other server.
60 |
61 |
62 |
63 |
64 | This permit might consequently be terminated if you disregard any of
65 | these confinements and may be ended by react-firebase-essentials.com
66 | whenever deemed. After permit termination or when your viewing permit
67 | is terminated, you must destroy any downloaded materials in your
68 | ownership whether in electronic or printed form.
69 |
70 |
71 |
3. Disclaimer
72 |
73 |
74 | The materials on react-firebase-essentials.com's site are given "as
75 | is". react-firebase-essentials.com makes no guarantees, communicated
76 | or suggested, and thus renounces and nullifies every single other
77 | warranties, including without impediment, inferred guarantees or
78 | states of merchantability, fitness for a specific reason, or
79 | non-encroachment of licensed property or other infringement of rights.
80 | Further, react-firebase-essentials.com does not warrant or make any
81 | representations concerning the precision, likely results, or
82 | unwavering quality of the utilization of the materials on its Internet
83 | site or generally identifying with such materials or on any
84 | destinations connected to this website.
85 |
86 |
87 |
4. Constraints
88 |
89 | In no occasion should react-firebase-essentials.com or its suppliers
90 | subject for any harms (counting, without constraint, harms for loss of
91 | information or benefit, or because of business interference,) emerging
92 | out of the utilization or powerlessness to utilize the materials on
93 | react-firebase-essentials.com's Internet webpage, regardless of the
94 | possibility that react-firebase-essentials.com or a
95 | react-firebase-essentials.com approved agent has been told orally or in
96 | written of the likelihood of such harm. Since a few purviews don't
97 | permit constraints on inferred guarantees, or impediments of obligation
98 | for weighty or coincidental harms, these confinements may not make a
99 | difference to you.
100 |
101 |
5. Amendments and Errata
102 |
103 | The materials showing up on react-firebase-essentials.com's site could
104 | incorporate typographical, or photographic mistakes.
105 | react-firebase-essentials.com does not warrant that any of the materials
106 | on its site are exact, finished, or current.
107 | react-firebase-essentials.com may roll out improvements to the materials
108 | contained on its site whenever without notification.
109 | react-firebase-essentials.com does not, then again, make any dedication
110 | to update the materials.
111 |
112 |
6. Links
113 |
114 | react-firebase-essentials.com has not checked on the majority of the
115 | websites or links connected to its website and is not in charge of the
116 | substance of any such connected webpage. The incorporation of any
117 | connection does not infer support by react-firebase-essentials.com of
118 | the site. Utilization of any such connected site is at the user's own
119 | risk.
120 |
121 |
7. Site Terms of Use Modifications
122 |
123 | react-firebase-essentials.com may update these terms of utilization for
124 | its website whenever without notification. By utilizing this site you
125 | are consenting to be bound by the then current form of these Terms and
126 | Conditions of Use.
127 |
128 |
8. Governing Law
129 |
130 | Any case identifying with react-firebase-essentials.com's site should be
131 | administered by the laws of the country of United States
132 | react-firebase-essentials.com State without respect to its contention of
133 | law provisions.
134 |
135 |
General Terms and Conditions applicable to Use of a Web Site.
136 |
Privacy Policy
137 |
138 | Your privacy is critical to us. Likewise, we have built up this Policy
139 | with the end goal you should see how we gather, utilize, impart and
140 | reveal and make utilization of individual data. The following blueprints
141 | our privacy policy.
142 |
143 |
144 |
145 | Before or at the time of collecting personal information, we will
146 | identify the purposes for which information is being collected.
147 |
148 |
149 | We will gather and utilization of individual data singularly with the
150 | target of satisfying those reasons indicated by us and for other good
151 | purposes, unless we get the assent of the individual concerned or as
152 | required by law.
153 |
154 |
155 | We will just hold individual data the length of essential for the
156 | satisfaction of those reasons.
157 |
158 |
159 | We will gather individual data by legal and reasonable means and,
160 | where fitting, with the information or assent of the individual
161 | concerned.
162 |
163 |
164 | Personal information ought to be important to the reasons for which it
165 | is to be utilized, and, to the degree essential for those reasons,
166 | ought to be exact, finished, and updated.
167 |
168 |
169 | We will protect individual data by security shields against misfortune
170 | or burglary, and also unapproved access, divulgence, duplicating, use
171 | or alteration.
172 |
173 |
174 | We will promptly provide customers with access to our policies and
175 | procedures for the administration of individual data.
176 |
177 |
178 |
179 | We are focused on leading our business as per these standards with a
180 | specific end goal to guarantee that the privacy of individual data is
181 | secure and maintained.
182 |
149 | Signing in and signing up are the same process, and no password is
150 | asked for...hopefully you don't mind! I believe that verification by
151 | email is better for consumer trust in the era of so many data
152 | breaches, and is arguably safer than a traditional authentication
153 | setup.
154 |
155 |
170 |
171 | OR
172 |
173 |
178 |
179 |
180 | >
181 | );
182 | };
183 |
184 | export default SignIn;
185 |
--------------------------------------------------------------------------------
/src/contexts/toastContext.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | export const ToastContext = React.createContext("");
4 |
5 | export const ToastProvider = props => {
6 | const [message, sendMessage] = useState("");
7 | return (
8 |
9 | {props.children}
10 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/src/contexts/userContext.js:
--------------------------------------------------------------------------------
1 | import React, { useReducer, createContext } from "react";
2 | const styleMode = window.localStorage.getItem("styleMode");
3 |
4 | const initialState = {
5 | userId: null,
6 | userData: {
7 | email: null,
8 | firstName: null,
9 | lastName: null,
10 | pushTokenWeb: null
11 | },
12 | styleMode: styleMode ? styleMode : "main",
13 | verifying: false
14 | };
15 | export const UserContext = createContext(initialState);
16 |
17 | const reducer = (state, action) => {
18 | switch (action.type) {
19 | case "userId":
20 | return { ...state, userId: action.payload };
21 | case "verifying":
22 | return { ...state, verifying: action.payload };
23 | case "updateProfile":
24 | return {
25 | ...state,
26 | userData: {
27 | ...state.userData,
28 | ...action.payload
29 | }
30 | };
31 | case "styleMode":
32 | return { ...state, styleMode: action.payload };
33 | case "signOut":
34 | return { ...initialState };
35 | default:
36 | return state;
37 | }
38 | };
39 |
40 | export const UserProvider = props => {
41 | const [userState, userDispatch] = useReducer(reducer, initialState);
42 | return (
43 |
44 | {props.children}
45 |
46 | );
47 | };
48 |
--------------------------------------------------------------------------------
/src/firebase.js:
--------------------------------------------------------------------------------
1 | import * as firebase from "firebase/app";
2 | import "firebase/messaging";
3 | import "firebase/auth";
4 | import "firebase/functions";
5 | const config = {
6 | apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
7 | authDomain: process.env.REACT_APP_FIREBASE_DOMAIN,
8 | projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
9 | messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_ID
10 | };
11 | firebase.initializeApp(config);
12 |
13 | if ("Notification" in window) {
14 | const messaging = firebase.messaging();
15 | messaging.usePublicVapidKey(process.env.REACT_APP_FIREBASE_MESSAGING_CERT);
16 |
17 | messaging.onMessage(payload => {
18 | console.log("Message received. ", payload);
19 | // push message to UI
20 | });
21 |
22 | messaging.onTokenRefresh(() => {
23 | const db = firebase.firestore();
24 | messaging
25 | .getToken()
26 | .then(refreshedToken => {
27 | db.collection("users")
28 | .doc(firebase.auth().currentUser.uid)
29 | .update({ pushTokenWeb: refreshedToken })
30 | .then(() => {
31 | console.log("Token updated.");
32 | })
33 | .catch(err => console.log(err));
34 | })
35 | .catch(err => {
36 | console.log("Unable to retrieve refreshed token ", err);
37 | });
38 | });
39 | }
40 |
41 | export default firebase;
42 |
--------------------------------------------------------------------------------
/src/helpers/cloudFunctions.js:
--------------------------------------------------------------------------------
1 | import firebase from "../firebase.js";
2 |
3 | export const sendPushNotification = data => {
4 | if (data.token) {
5 | const push = firebase.functions().httpsCallable("sendPushNotification");
6 | push({
7 | token: data.token,
8 | title: data.title,
9 | body: data.body
10 | });
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eemebarbe/react-firebase-essentials/487d0edb0ae05238db41e0a444b9a8b01288bed4/src/index.css
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: http://bit.ly/CRA-PWA
12 | serviceWorker.unregister();
13 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read http://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/themes/GlobalStyle.js:
--------------------------------------------------------------------------------
1 | import { metrics } from "../themes";
2 | import { createGlobalStyle } from "styled-components";
3 |
4 | const GlobalStyle = createGlobalStyle`
5 | @import url('https://fonts.googleapis.com/css?family=Questrial&display=swap');
6 | html {
7 | height: 100%;
8 | width: 100%;
9 | overflow: hidden;
10 | font-size: ${metrics.baseUnit}px;
11 | background-color: ${props => props.theme.background};
12 | color: ${props => props.theme.mainText};
13 | @media (max-width: 480px){
14 | font-size: ${metrics.baseUnit}px;
15 | }
16 | }
17 | body {
18 | input, textarea, button {
19 | font-family: inherit;
20 | }
21 | font-family: 'Questrial', sans-serif;
22 | margin: 0;
23 | padding: 0;
24 | -webkit-font-smooth: antialiased;
25 | -moz-osx-font-smoothing: grayscale;
26 | height: 100%;
27 | width: 100%;
28 | overflow: hidden;
29 | list-style-position: inside;
30 | -webkit-tap-highlight-color: rgba(0,0,0,0);
31 | input:-webkit-autofill,
32 | input:-webkit-autofill:hover,
33 | input:-webkit-autofill:focus,
34 | input:-webkit-autofill:active {
35 | -webkit-box-shadow: 0 0 0px 1000px ${props =>
36 | props.theme.background} inset;
37 | box-shadow: 0 0 0px 1000px ${props => props.theme.background} inset;
38 | -webkit-text-fill-color: ${props => props.theme.mainText} !important;
39 | background-color: ${props => props.theme.background} !important;
40 | }
41 | }
42 | #root {
43 | height: 100%;
44 | }`;
45 |
46 | export default GlobalStyle;
47 |
--------------------------------------------------------------------------------
/src/themes/colors.js:
--------------------------------------------------------------------------------
1 | const main = {
2 | inactive: "rgb(211, 211, 211)",
3 | primaryButton: "rgb(0, 0, 255)",
4 | mainText: "rgb(0, 0, 0)",
5 | detailText: "rgb(255, 255, 255)",
6 | secondaryColor: "rgb(255,0,0)",
7 | background: "rgb(255, 255, 255)",
8 | overlayBackground: "rgb(211, 211, 211)",
9 | overlayDetail: "rgb(169,169,169)"
10 | };
11 |
12 | const dark = {
13 | inactive: "rgb(120, 120, 120)",
14 | primaryButton: "rgb(0, 0, 255)",
15 | mainText: "rgb(255, 255, 255)",
16 | detailText: "rgb(255, 255, 255)",
17 | secondaryColor: "rgb(255,0,0)",
18 | background: "rgb(40, 40, 40)",
19 | overlayBackground: "rgb(40, 40, 40)",
20 | overlayDetail: "rgb(68,68,68)"
21 | };
22 |
23 | const colors = {
24 | main: main,
25 | dark: dark
26 | };
27 |
28 | export default colors;
29 |
--------------------------------------------------------------------------------
/src/themes/icons.js:
--------------------------------------------------------------------------------
1 | import facebook from "./icons/flogo-HexRBG-Wht-72.svg";
2 | import google from "./icons/icons8-google-48.png";
3 | import github from "./icons/github.svg";
4 |
5 | const icons = {
6 | google: google,
7 | facebook: facebook,
8 | github: github
9 | };
10 |
11 | export default icons;
12 |
--------------------------------------------------------------------------------
/src/themes/icons/btn_google_signin_light_normal_web@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eemebarbe/react-firebase-essentials/487d0edb0ae05238db41e0a444b9a8b01288bed4/src/themes/icons/btn_google_signin_light_normal_web@2x.png
--------------------------------------------------------------------------------
/src/themes/icons/flogo-HexRBG-Wht-72.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/themes/icons/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/themes/icons/icons8-google-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eemebarbe/react-firebase-essentials/487d0edb0ae05238db41e0a444b9a8b01288bed4/src/themes/icons/icons8-google-48.png
--------------------------------------------------------------------------------
/src/themes/icons/icons8-google-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eemebarbe/react-firebase-essentials/487d0edb0ae05238db41e0a444b9a8b01288bed4/src/themes/icons/icons8-google-96.png
--------------------------------------------------------------------------------
/src/themes/index.js:
--------------------------------------------------------------------------------
1 | import colors from "./colors";
2 | import metrics from "./metrics";
3 | import icons from "./icons";
4 |
5 | export { colors, metrics, icons };
6 |
--------------------------------------------------------------------------------
/src/themes/metrics.js:
--------------------------------------------------------------------------------
1 | const metrics = {
2 | baseUnit: 12,
3 | baseFontUnit: 12,
4 | globalBorderRadius: 4,
5 | get bodyWidth() {
6 | return this.baseUnit * 64;
7 | },
8 | get bodyPadding() {
9 | return this.baseUnit * 2;
10 | },
11 | get mobileMenuHeight() {
12 | return this.baseUnit * 4;
13 | },
14 | get headerHeight() {
15 | return this.baseUnit * 6;
16 | },
17 | get smallText() {
18 | return this.baseFontUnit * 1.25;
19 | },
20 | get regularText() {
21 | return this.baseFontUnit * 1.5;
22 | },
23 | get H1() {
24 | return this.baseFontUnit * 4;
25 | },
26 | get H2() {
27 | return this.baseFontUnit * 2;
28 | },
29 | get H1Mobile() {
30 | return this.baseFontUnit * 3.5;
31 | },
32 | animationLength: 400
33 | };
34 |
35 | export default metrics;
36 |
--------------------------------------------------------------------------------
/storage.rules:
--------------------------------------------------------------------------------
1 | service firebase.storage {
2 | match /b/{bucket}/o {
3 | match /{allPaths=**} {
4 | allow read, write: if request.auth!=null;
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------