├── .eslintignore ├── src ├── components │ ├── .gitkeep │ ├── Layout │ │ ├── Layout.module.scss │ │ ├── index.jsx │ │ └── Layout.test.js │ ├── Navigation │ │ ├── Aside │ │ │ ├── Aside.module.scss │ │ │ ├── __snapshots__ │ │ │ │ └── Aside.test.js.snap │ │ │ ├── Aside.test.js │ │ │ └── index.jsx │ │ ├── Link │ │ │ ├── __snapshots__ │ │ │ │ └── Link.test.js.snap │ │ │ ├── index.jsx │ │ │ └── Link.test.js │ │ ├── Footer │ │ │ ├── Footer.module.scss │ │ │ ├── Footer.test.js │ │ │ ├── index.jsx │ │ │ └── __snapshots__ │ │ │ │ └── Footer.test.js.snap │ │ └── NavBar │ │ │ ├── NavBar.test.js │ │ │ ├── __snapshots__ │ │ │ └── NavBar.test.js.snap │ │ │ └── index.jsx │ ├── ConfirmationModal │ │ ├── ConfirmationModal.scss │ │ ├── __snapshots__ │ │ │ └── ConfirmationModal.test.js.snap │ │ ├── index.jsx │ │ └── ConfirmationModal.test.js │ ├── ErrorMessage │ │ ├── __snapshots__ │ │ │ └── ErrorMessage.test.js.snap │ │ ├── ErrorMessage.test.js │ │ └── index.jsx │ ├── UserForm │ │ ├── UserForm.scss │ │ └── UserForm.test.js │ ├── Table │ │ ├── Table.module.scss │ │ └── TableMobile.css │ ├── DatePicker │ │ ├── __snapshots__ │ │ │ └── DatePicker.test.js.snap │ │ ├── DatePicker.scss │ │ ├── DatePicker.test.js │ │ └── index.jsx │ └── LanguageWrapper │ │ └── index.js ├── styles │ └── .gitkeep ├── pages │ ├── NotFound │ │ ├── NotFound.module.scss │ │ ├── __snapshots__ │ │ │ └── NotFound.test.js.snap │ │ ├── NotFound.test.js │ │ └── index.jsx │ ├── Login │ │ ├── Login.module.scss │ │ ├── Login.test.js │ │ └── __snapshots__ │ │ │ └── Login.test.js.snap │ ├── ResetPassword │ │ ├── ResetPassword.module.scss │ │ ├── __snapshots__ │ │ │ └── ResetPassword.test.js.snap │ │ ├── ResetPassword.test.js │ │ └── index.jsx │ ├── Router │ │ ├── paths.js │ │ ├── Router.test.js │ │ ├── PrivateRoute │ │ │ ├── index.js │ │ │ └── PrivateRoute.test.js │ │ └── index.js │ ├── Section │ │ ├── Section.test.js │ │ ├── index.jsx │ │ └── __snapshots__ │ │ │ └── Section.test.js.snap │ ├── Submenu │ │ ├── Submenu.test.js │ │ ├── index.jsx │ │ └── __snapshots__ │ │ │ └── Submenu.test.js.snap │ ├── Users │ │ ├── Users.module.scss │ │ ├── Users.test.js │ │ └── index.jsx │ ├── Home │ │ ├── index.jsx │ │ ├── __snapshots__ │ │ │ └── Home.test.js.snap │ │ └── Home.test.js │ ├── Profile │ │ ├── Profile.test.js │ │ ├── index.jsx │ │ └── ChangePassword │ │ │ ├── __snapshots__ │ │ │ └── ChangePassword.test.js.snap │ │ │ ├── ChangePassword.test.js │ │ │ └── index.jsx │ └── User │ │ ├── User.test.js │ │ └── index.jsx ├── assets │ ├── en.png │ ├── es.png │ ├── 404.gif │ ├── default-image-establishment.jpg │ └── user-default-log.svg ├── state │ ├── actions │ │ └── preferences.js │ ├── api │ │ ├── index.js │ │ ├── rtdb.js │ │ └── firestore.js │ ├── reducers │ │ ├── preferences │ │ │ ├── index.js │ │ │ └── preferences.test.js │ │ ├── index.js │ │ ├── users │ │ │ ├── index.js │ │ │ └── users.test.js │ │ └── auth │ │ │ └── index.js │ └── store.js ├── firebase.js ├── hooks │ └── index.js ├── index.scss ├── index.js ├── setupTests.js ├── utils │ └── index.js ├── languages │ ├── en.json │ └── es.json └── serviceWorker.js ├── .prettierrc ├── firestore.indexes.json ├── functions ├── src │ ├── types │ │ └── firebase-function-tools.d.ts │ ├── db │ │ └── users │ │ │ ├── onDelete.function.ts │ │ │ └── onUpdate.function.ts │ ├── firestore │ │ └── users │ │ │ ├── onDelete.function.ts │ │ │ └── onUpdate.function.ts │ ├── index.ts │ └── https │ │ └── createUser.function.ts ├── env.example.json ├── .gitignore ├── tsconfig.json ├── test │ ├── util │ │ └── config.ts │ ├── db │ │ └── users │ │ │ ├── onDelete.test.ts │ │ │ └── onUpdate.test.ts │ ├── firestore │ │ └── users │ │ │ ├── onDelete.test.ts │ │ │ └── onUpdate.test.ts │ └── https │ │ └── createUser.test.ts ├── package.json ├── setupProject.js └── tslint.json ├── jsconfig.json ├── .firebaserc ├── storage.rules ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── production-deployment.yml │ ├── staging-deployment.yml │ └── pull-requests.yml ├── .env.example ├── database.rules.json ├── firebase.json ├── firestore.rules ├── LICENSE.md ├── .eslintrc ├── .gitignore ├── public └── index.html └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | build/* -------------------------------------------------------------------------------- /src/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [], 3 | "fieldOverrides": [] 4 | } 5 | -------------------------------------------------------------------------------- /src/pages/NotFound/NotFound.module.scss: -------------------------------------------------------------------------------- 1 | .section { 2 | margin: 0 auto; 3 | } 4 | -------------------------------------------------------------------------------- /functions/src/types/firebase-function-tools.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'firebase-function-tools'; 2 | -------------------------------------------------------------------------------- /src/assets/en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateThrive/react-firebase-admin/HEAD/src/assets/en.png -------------------------------------------------------------------------------- /src/assets/es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateThrive/react-firebase-admin/HEAD/src/assets/es.png -------------------------------------------------------------------------------- /src/assets/404.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateThrive/react-firebase-admin/HEAD/src/assets/404.gif -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Layout/Layout.module.scss: -------------------------------------------------------------------------------- 1 | .layout { 2 | min-height: calc(100vh - 100px); 3 | background-color: white; 4 | } -------------------------------------------------------------------------------- /src/components/Navigation/Aside/Aside.module.scss: -------------------------------------------------------------------------------- 1 | .submenuLink:hover { 2 | background-color: #262930; 3 | color: white; 4 | } 5 | -------------------------------------------------------------------------------- /functions/env.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "databaseURL": "", 3 | "storageBucket": "", 4 | "projectId": "", 5 | "serviceAccountKey": "" 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/default-image-establishment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CreateThrive/react-firebase-admin/HEAD/src/assets/default-image-establishment.jpg -------------------------------------------------------------------------------- /src/components/ConfirmationModal/ConfirmationModal.scss: -------------------------------------------------------------------------------- 1 | header.modal-card-head, 2 | footer.modal-card-foot { 3 | border: 1px solid #f1f2f2; 4 | background: white; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Navigation/Link/__snapshots__/Link.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` rendering should render without crashing 1`] = `undefined`; 4 | -------------------------------------------------------------------------------- /src/pages/Login/Login.module.scss: -------------------------------------------------------------------------------- 1 | .errorMessage { 2 | margin: 0.7rem 0 0 0; 3 | } 4 | .socialButtons { 5 | flex-direction: column; 6 | } 7 | .icon { 8 | margin-right: 5px; 9 | } 10 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "production": "react-firebase-admin-eeac2", 4 | "staging": "react-firebase-admin-eeac2", 5 | "default": "react-firebase-admin-eeac2" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /storage.rules: -------------------------------------------------------------------------------- 1 | service firebase.storage { 2 | match /b/{bucket}/o { 3 | match /users/{imageId} { 4 | allow write: if request.auth!=null; 5 | allow read: if true; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/ResetPassword/ResetPassword.module.scss: -------------------------------------------------------------------------------- 1 | .sub-title { 2 | margin: 0 0 1rem 0; 3 | } 4 | 5 | .errorMessage { 6 | margin: 0.7rem 0 0 0; 7 | } 8 | 9 | .return-login { 10 | display: block; 11 | margin: 1rem 0 0 0; 12 | } 13 | -------------------------------------------------------------------------------- /functions/.gitignore: -------------------------------------------------------------------------------- 1 | ## Compiled JavaScript files 2 | **/*.js 3 | **/*.js.map 4 | 5 | # Typescript v1 declaration files 6 | typings/ 7 | 8 | node_modules/ 9 | 10 | lib/ 11 | 12 | #Necessary config for testing 13 | env.json 14 | 15 | service-account-key.json -------------------------------------------------------------------------------- /src/state/actions/preferences.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-act'; 2 | 3 | export const PREFERENCES_SET_LOCALE = createAction('PREFERENCES_SET_LOCALE'); 4 | 5 | export const setUserLocale = locale => dispatch => { 6 | return dispatch(PREFERENCES_SET_LOCALE({ locale })); 7 | }; 8 | -------------------------------------------------------------------------------- /functions/src/db/users/onDelete.function.ts: -------------------------------------------------------------------------------- 1 | import { auth } from 'firebase-admin'; 2 | import { database } from 'firebase-functions'; 3 | 4 | export default database.ref('users/{uid}').onDelete((snapshot, context) => { 5 | const { uid } = context.params; 6 | return auth().deleteUser(uid); 7 | }); 8 | -------------------------------------------------------------------------------- /src/state/api/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | createDocument, 3 | deleteDocument, 4 | fetchCollection, 5 | fetchDocument, 6 | updateDocument, 7 | } from './rtdb'; 8 | 9 | export { 10 | createDocument, 11 | deleteDocument, 12 | fetchCollection, 13 | fetchDocument, 14 | updateDocument, 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/Navigation/Footer/Footer.module.scss: -------------------------------------------------------------------------------- 1 | footer { 2 | border-top: 1px solid #f1f2f2; 3 | } 4 | 5 | .level { 6 | display: flex; 7 | } 8 | 9 | @media screen and (max-width: 768px) { 10 | .level span { 11 | display: none; 12 | } 13 | .levelRight { 14 | margin-top: 0 !important; 15 | } 16 | } -------------------------------------------------------------------------------- /src/components/ErrorMessage/__snapshots__/ErrorMessage.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[` rendering should render without crashing 1`] = ` 4 | 5 |

8 | This field is required 9 |

10 |
11 | `; 12 | -------------------------------------------------------------------------------- /src/pages/Router/paths.js: -------------------------------------------------------------------------------- 1 | export default { 2 | ROOT: '/', 3 | LOGIN: '/login', 4 | USERS: '/users', 5 | ADD_USER: '/users/new', 6 | MODIFY_USER: '/users/:id', 7 | PROFILE: '/profile', 8 | RESET_PASSWORD: '/recover-password', 9 | SECTION: '/section', 10 | SUBMENU_1: '/submenu1', 11 | SUBMENU_2: '/submenu2' 12 | }; 13 | -------------------------------------------------------------------------------- /functions/src/firestore/users/onDelete.function.ts: -------------------------------------------------------------------------------- 1 | import { auth } from 'firebase-admin'; 2 | import { firestore } from 'firebase-functions'; 3 | 4 | export default firestore 5 | .document('users/{uid}') 6 | .onDelete((snapshot, context) => { 7 | const { uid } = context.params; 8 | return auth().deleteUser(uid); 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/UserForm/UserForm.scss: -------------------------------------------------------------------------------- 1 | .is-user-avatar { 2 | &.has-max-width { 3 | max-height: 7rem; 4 | } 5 | 6 | .user-avatar { 7 | height: 100%; 8 | max-height: 7rem; 9 | max-width: 7rem; 10 | } 11 | } 12 | 13 | @media screen and (max-width: 768px) { 14 | div.preview { 15 | display: none; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/pages/Section/Section.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Section from '.'; 4 | 5 | describe('
rendering', () => { 6 | it('should render without crashing', () => { 7 | const { component } = renderWithProviders(
)({}); 8 | 9 | expect(component.asFragment()).toMatchSnapshot(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/pages/Submenu/Submenu.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Submenu from '.'; 4 | 5 | describe(' rendering', () => { 6 | it('should render without crashing', () => { 7 | const { component } = renderWithProviders()({}); 8 | 9 | expect(component.asFragment()).toMatchSnapshot(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/components/ErrorMessage/ErrorMessage.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import ErrorMessage from '.'; 4 | 5 | describe(' rendering', () => { 6 | it('should render without crashing', () => { 7 | const { component } = renderWithProviders()({}); 8 | 9 | expect(component.asFragment()).toMatchSnapshot(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/components/Navigation/Footer/Footer.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import Footer from '.'; 4 | 5 | describe('