├── .gitignore
├── LICENSE
├── README.md
├── babel.config.cjs.json
├── babel.config.esm.json
├── dist
├── cjs
│ ├── assets
│ │ └── images
│ │ │ ├── google.svg
│ │ │ └── microsoft.svg
│ ├── components
│ │ ├── Auth.js
│ │ ├── Fireact.js
│ │ ├── SetPageTitle.js
│ │ ├── auth
│ │ │ ├── ActionPages.js
│ │ │ ├── ResetPassword.js
│ │ │ ├── SignIn.js
│ │ │ └── SignUp.js
│ │ ├── menus
│ │ │ ├── MainMenu.js
│ │ │ └── UserMenu.js
│ │ ├── templates
│ │ │ ├── AppTemplate.js
│ │ │ └── PublicTemplate.js
│ │ └── user
│ │ │ ├── UserDelete.js
│ │ │ ├── UserProfile.js
│ │ │ ├── UserUpdateEmail.js
│ │ │ ├── UserUpdateName.js
│ │ │ └── UserUpdatePassword.js
│ ├── index.js
│ └── pathnames.json
└── esm
│ ├── assets
│ └── images
│ │ ├── google.svg
│ │ └── microsoft.svg
│ ├── components
│ ├── Auth.js
│ ├── Fireact.js
│ ├── SetPageTitle.js
│ ├── auth
│ │ ├── ActionPages.js
│ │ ├── ResetPassword.js
│ │ ├── SignIn.js
│ │ └── SignUp.js
│ ├── menus
│ │ ├── MainMenu.js
│ │ └── UserMenu.js
│ ├── templates
│ │ ├── AppTemplate.js
│ │ └── PublicTemplate.js
│ └── user
│ │ ├── UserDelete.js
│ │ ├── UserProfile.js
│ │ ├── UserUpdateEmail.js
│ │ ├── UserUpdateName.js
│ │ └── UserUpdatePassword.js
│ ├── index.js
│ └── pathnames.json
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── authMethods.json
├── index.css
├── index.js
├── lib
├── assets
│ └── images
│ │ ├── google.svg
│ │ └── microsoft.svg
├── components
│ ├── Auth.js
│ ├── Fireact.js
│ ├── SetPageTitle.js
│ ├── auth
│ │ ├── ActionPages.js
│ │ ├── ResetPassword.js
│ │ ├── SignIn.js
│ │ └── SignUp.js
│ ├── menus
│ │ ├── MainMenu.js
│ │ └── UserMenu.js
│ ├── templates
│ │ ├── AppTemplate.js
│ │ └── PublicTemplate.js
│ └── user
│ │ ├── UserDelete.js
│ │ ├── UserProfile.js
│ │ ├── UserUpdateEmail.js
│ │ ├── UserUpdateName.js
│ │ └── UserUpdatePassword.js
├── index.js
└── pathnames.json
├── reportWebVitals.js
└── setupTests.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 | .env.*
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 | firebase.json
26 | src/firebaseConfig.json
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright 2022 Hey Data Pty Ltd
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## What is @fireactjs/core?
2 |
3 | fireactjs-core is the core package for building web applications with Firebase and Reactjs in a simple and fast approach. Its key features include:
4 |
5 | - Built-in Firebase authentication features for users to sign up and sign in
6 | - Built-in user profile features for users to change email, and password and delete user accounts
7 | - Template base design for easy customization
8 | - Component base architecture that supports full customization
9 | - Easy to extend additional features
10 |
11 | ## Live demo
12 |
13 | To experience the package, go to [https://demo.fireactjs.com](https://demo.fireactjs.com)
14 |
15 | ## Documentation
16 |
17 | For documentation of the package, go to [https://fireactjs.com/docs/core-package/](https://fireactjs.com/docs/core-package/)
18 |
19 | ## Installation
20 |
21 | To install the fireactjs-core components, create your Reactjs project first, and then run `npm I @fireactjs/core` to install the components.
22 |
23 | ```jsx
24 | npx create-react-app my-app
25 | cd my-app
26 | npm i @fireactjs/core react-router-dom firebase @mui/material @mui/icons-material @emotion/react @emotion/styled
27 | ```
28 |
29 | For details on how to create a Reactjs application, please see [https://reactjs.org/docs/create-a-new-react-app.html](https://reactjs.org/docs/create-a-new-react-app.html)
30 |
31 | ## Setup your Firebase project
32 |
33 | As @fireactjs/core is built on Firebase and Reactjs, you will need to have a Firebase project. Go to [the Firebase website](https://firebase.google.com/) and create a project.
34 |
35 | ### Create a web app
36 |
37 | In your Firebase Project settings → General, click the “Add app” button to create a new web app. You will the instructions on install the firebase npm package and a JSON configuration named `firebaseConfig` which you will need to configure your @fireactjs application.
38 |
39 | Create a file called `firebaseConfig.json` in the `/src` folder and copy the `firebaseConfig` JSON to the file similar to the format below.
40 |
41 | ```json
42 | {
43 | "apiKey": "...",
44 | "authDomain": "...",
45 | "projectId": "...",
46 | "storageBucket": "...",
47 | "messagingSenderId": "...",
48 | "appId": "..."
49 | }
50 | ```
51 |
52 | ### Enable authentication methods
53 |
54 | After you create your Firebase project, go to the project console and enable the authentication methods you plan to use for your web application. @fireactjs/core supports the following authentication methods:
55 |
56 | - Email and password
57 | - Google
58 | - Facebook
59 | - Microsoft
60 | - Twitter
61 | - Github
62 | - Apple
63 |
64 | Some of the authentication methods require you to register your web application in the authentication platforms (e.g. Facebook). Please make sure you complete the necessary steps to enable the authentication methods.
65 |
66 | Create a file called `authMethods.json` in the `/src` folder and copy the following JSON to the file, then set the authentication methods that you enabled to `true` otherwise to `false`.
67 |
68 | ```json
69 | {
70 | "google": true,
71 | "facebook": true,
72 | "microsoft": true,
73 | "apple": true,
74 | "twitter": true,
75 | "github": true
76 | }
77 | ```
78 |
79 | ### Initialize your Firebase project
80 |
81 | Run `firebase login` to sign in to your Firebase account and then run `firebase init` to initialize your Firebase project locally.
82 |
83 | ### Update Firestore rules
84 |
85 | Update your `firebase.rules` with the code below.
86 |
87 | ```
88 | rules_version = '2';
89 | service cloud.firestore {
90 | match /databases/{database}/documents {
91 | match /{document=**} {
92 | allow read, write: if false;
93 | }
94 | match /users/{userId} {
95 | allow read, update, create: if request.auth.uid == userId;
96 | }
97 | }
98 | }
99 | ```
100 |
101 | ## Modify App.js
102 |
103 | Replace the code in your `src/App.js` with the code below. You can copy the code from [https://github.com/fireactjs/core-demo/blob/main/src/App.js](https://github.com/fireactjs/core-demo/blob/main/src/App.js)
104 |
105 | ```jsx
106 | import './App.css';
107 | import firebaseConfig from "./firebaseConfig.json";
108 | import { pathnames, ActionPages, AppTemplate, AuthProvider, AuthRoutes, FireactProvider, MainMenu, PublicTemplate, ResetPassword, SignIn, SignUp, UserMenu, UserProfile, UserUpdateEmail, UserUpdateName, UserUpdatePassword, UserDelete } from '@fireactjs/core';
109 | import { BrowserRouter, Routes } from "react-router-dom";
110 | import { Route } from "react-router-dom";
111 | import LocalFireDepartmentIcon from '@mui/icons-material/LocalFireDepartment';
112 | import { CircularProgress, Box } from '@mui/material';
113 | import authMethods from "./authMethods.json";
114 |
115 | const Logo = ({size, color}) => {
116 | const logoColor = color || 'warning';
117 | return (
118 |
119 | );
120 | }
121 |
122 | const Loader = ({size}) => {
123 | let cpSize = "35px";
124 | switch(size){
125 | case "small":
126 | cpSize = "30px";
127 | break;
128 | case "medium":
129 | cpSize = "35px";
130 | break;
131 | case "large":
132 | cpSize = "45px";
133 | break;
134 | default:
135 | cpSize = "35px";
136 | break;
137 | }
138 | return (
139 |
140 |
141 |
142 |
143 |
144 |
145 | );
146 | }
147 |
148 | function App() {
149 |
150 | const config = {
151 | firebaseConfig: firebaseConfig,
152 | brand: "FIREACTJS",
153 | pathnames: pathnames,
154 | authProviders: authMethods
155 | }
156 |
157 | return (
158 |
159 |
160 |
161 |
162 | } />} >
163 | } toolBarMenu={} drawerMenu={} />}>
164 | >} />
165 | } />
166 | } />
167 | } />
168 | } />
169 | } />
170 |
171 |
172 | }>
173 | }
176 | />
177 | } />
178 | }
181 | />
182 | } />
183 | }
186 | />
187 | } />
188 | }
191 | />
192 | } />
193 |
194 |
195 |
196 |
197 |
198 | )
199 | }
200 |
201 | export default App;
202 |
203 | ```
204 |
205 | Replace `Brand` and `Logo` to customise the logo and the brand of your web application.
206 |
207 | For further customisation, please read the documentation.
208 |
209 | ## Update Firebase template action URL (Optional)
210 |
211 | Go to your Firebase project authentication → Templates, then click on the Edit Template button, and then click on “Customize action URL”. Use `https://www.yourdomain.com/auth-action` as the custom action URL and replace `www.yourdomain.com` with your actual application domain.
212 |
213 | ## Run your app locally
214 |
215 | By now, your app is ready for the first run locally. Use the command `npm start` to start the app.
216 |
217 | ## Deploy to Firebase
218 |
219 | After testing locally, your app is ready to be deployed to Firebase hosting.
220 |
221 | ### Build
222 |
223 | Run `npm run build` to build your app
224 |
225 | ### Deploy
226 |
227 | Run `firebase init` to initialize your project with Firebase and then run `firebase deploy` to deploy your app to Firebase. If you see a blank screen in your production URL, make sure you set the `build` as the folder in your Firebase settings.
--------------------------------------------------------------------------------
/babel.config.cjs.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/env",
5 | {
6 | "targets": {
7 | "edge": "17",
8 | "firefox": "60",
9 | "chrome": "67",
10 | "safari": "11.1"
11 | },
12 | "modules": "cjs",
13 | "useBuiltIns": "usage",
14 | "corejs": "3.6.5"
15 | }
16 | ],
17 | "@babel/preset-react"
18 | ]
19 | }
--------------------------------------------------------------------------------
/babel.config.esm.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/env",
5 | {
6 | "targets": {
7 | "edge": "17",
8 | "firefox": "60",
9 | "chrome": "67",
10 | "safari": "11.1"
11 | },
12 | "modules": false,
13 | "useBuiltIns": "usage",
14 | "corejs": "3.6.5"
15 | }
16 | ],
17 | "@babel/preset-react"
18 | ]
19 | }
--------------------------------------------------------------------------------
/dist/cjs/assets/images/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/dist/cjs/assets/images/microsoft.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dist/cjs/components/Auth.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.symbol.description.js");
4 | require("core-js/modules/es.weak-map.js");
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports.AuthRoutes = exports.AuthProvider = exports.AuthContext = void 0;
9 | require("core-js/modules/web.dom-collections.iterator.js");
10 | require("core-js/modules/es.regexp.exec.js");
11 | require("core-js/modules/es.string.search.js");
12 | var _react = _interopRequireWildcard(require("react"));
13 | var _app = require("firebase/app");
14 | var _auth = require("firebase/auth");
15 | var _reactRouterDom = require("react-router-dom");
16 | var _material = require("@mui/material");
17 | var _firestore = require("firebase/firestore");
18 | var _Fireact = require("./Fireact");
19 | var _functions = require("firebase/functions");
20 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
21 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
22 | function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
23 | function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
24 | function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
25 | function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
26 | function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
27 | const AuthContext = exports.AuthContext = /*#__PURE__*/_react.default.createContext();
28 | const AuthProvider = _ref => {
29 | let {
30 | children
31 | } = _ref;
32 | // authorized user state
33 | const [authUser, setAuthUser] = (0, _react.useState)({
34 | user: null,
35 | data: {},
36 | checked: false
37 | });
38 | const {
39 | config
40 | } = (0, _react.useContext)(_Fireact.FireactContext);
41 | const [firebaseApp, setFirebaseApp] = (0, _react.useState)(null);
42 | const [authInstance, setAuthInstance] = (0, _react.useState)(null);
43 | const [firestoreInstance, setFirestoreInstance] = (0, _react.useState)(null);
44 | const [functionsInstance, setFunctionsInstance] = (0, _react.useState)(null);
45 | (0, _react.useEffect)(() => {
46 | const app = (0, _app.initializeApp)(config.firebaseConfig);
47 | const auth = (0, _auth.getAuth)(app);
48 | const firestore = (0, _firestore.getFirestore)(app);
49 | const functions = (0, _functions.getFunctions)(app);
50 | setFirebaseApp(app);
51 | setAuthInstance(auth);
52 | setFirestoreInstance(firestore);
53 | setFunctionsInstance(functions);
54 | (0, _auth.onAuthStateChanged)(auth, user => {
55 | if (user !== null) {
56 | user.getIdToken().then(token => {
57 | const userDoc = (0, _firestore.doc)(firestore, 'users', user.uid);
58 | setAuthUser(prevState => _objectSpread(_objectSpread({}, prevState), {}, {
59 | user: user,
60 | checked: true
61 | }));
62 | (0, _firestore.setDoc)(userDoc, {
63 | displayName: user.displayName,
64 | photoURL: user.photoURL,
65 | email: user.email
66 | }, {
67 | merge: true
68 | });
69 | });
70 | } else {
71 | setAuthUser(prevState => _objectSpread(_objectSpread({}, prevState), {}, {
72 | user: null,
73 | checked: true
74 | }));
75 | }
76 | });
77 | }, [config.firebaseConfig]);
78 | return /*#__PURE__*/_react.default.createElement(AuthContext.Provider, {
79 | value: {
80 | authUser,
81 | setAuthUser,
82 | firebaseApp,
83 | authInstance,
84 | firestoreInstance,
85 | functionsInstance
86 | }
87 | }, children);
88 | };
89 | exports.AuthProvider = AuthProvider;
90 | const AuthRoutes = _ref2 => {
91 | let {
92 | loader
93 | } = _ref2;
94 | const {
95 | authUser
96 | } = (0, _react.useContext)(AuthContext);
97 | const {
98 | config
99 | } = (0, _react.useContext)(_Fireact.FireactContext);
100 | const signInPath = config.pathnames.SignIn;
101 | if (authUser.checked) {
102 | if (authUser.user !== null) {
103 | return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Outlet, null);
104 | } else {
105 | return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Navigate, {
106 | to: signInPath + "?re=" + document.location.pathname + document.location.search + document.location.hash
107 | });
108 | }
109 | } else {
110 | return /*#__PURE__*/_react.default.createElement(_material.Box, {
111 | mt: 10
112 | }, /*#__PURE__*/_react.default.createElement(_material.Container, {
113 | maxWidth: "sm"
114 | }, /*#__PURE__*/_react.default.createElement(_material.Box, {
115 | component: "span",
116 | m: 5,
117 | textAlign: "center"
118 | }, loader)));
119 | }
120 | };
121 | exports.AuthRoutes = AuthRoutes;
--------------------------------------------------------------------------------
/dist/cjs/components/Fireact.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.FireactProvider = exports.FireactContext = void 0;
7 | var _react = _interopRequireDefault(require("react"));
8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9 | const FireactContext = exports.FireactContext = /*#__PURE__*/_react.default.createContext();
10 | const FireactProvider = _ref => {
11 | let {
12 | config,
13 | children
14 | } = _ref;
15 | return /*#__PURE__*/_react.default.createElement(FireactContext.Provider, {
16 | value: {
17 | config
18 | }
19 | }, children);
20 | };
21 | exports.FireactProvider = FireactProvider;
--------------------------------------------------------------------------------
/dist/cjs/components/SetPageTitle.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | require("core-js/modules/web.dom-collections.iterator.js");
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports.SetPageTitle = void 0;
9 | var _react = _interopRequireWildcard(require("react"));
10 | var _Auth = require("./Auth");
11 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
12 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13 | const SetPageTitle = _ref => {
14 | let {
15 | title
16 | } = _ref;
17 | const {
18 | brand
19 | } = (0, _react.useContext)(_Auth.AuthContext);
20 | (0, _react.useEffect)(() => {
21 | document.title = brand ? "".concat(title, " - ").concat(brand) : title;
22 | }, [title, brand]);
23 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
24 | };
25 | exports.SetPageTitle = SetPageTitle;
--------------------------------------------------------------------------------
/dist/cjs/components/auth/ActionPages.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.ActionPages = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | require("core-js/modules/web.url.js");
10 | require("core-js/modules/web.url-search-params.js");
11 | require("core-js/modules/es.regexp.exec.js");
12 | require("core-js/modules/es.regexp.test.js");
13 | var _react = _interopRequireWildcard(require("react"));
14 | var _material = require("@mui/material");
15 | var _SetPageTitle = require("../SetPageTitle");
16 | var _auth = require("firebase/auth");
17 | var _reactRouterDom = require("react-router-dom");
18 | var _Fireact = require("../Fireact");
19 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
20 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
21 | const ActionPages = _ref => {
22 | let {
23 | logo
24 | } = _ref;
25 | let title = "Unknown Action";
26 | const params = new URL(document.location).searchParams;
27 | const mode = params.get('mode');
28 | const actionCode = params.get('oobCode');
29 | // const apiKey = params.get('apiKey');
30 | // const continueUrl = params.get('continueUrl');
31 | // const lang = params.get('lang') || 'en';
32 |
33 | switch (mode) {
34 | case 'resetPassword':
35 | title = "Reset Password";
36 | break;
37 | case 'recoverEmail':
38 | title = 'Recover Email';
39 | break;
40 | case 'verifyEmail':
41 | title = 'Verfiy Email';
42 | break;
43 | default:
44 | break;
45 | }
46 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
47 | title: title
48 | }), logo, /*#__PURE__*/_react.default.createElement(_material.Typography, {
49 | component: "h1",
50 | variant: "h5"
51 | }, title)), /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_material.Stack, {
52 | spacing: 2,
53 | mt: 2
54 | }, (mode === 'verifyEmail' || mode === 'recoverEmail') && /*#__PURE__*/_react.default.createElement(HandleAction, {
55 | actionCode: actionCode,
56 | mode: mode
57 | }), mode === 'resetPassword' && /*#__PURE__*/_react.default.createElement(ResetPassword, {
58 | actionCode: actionCode
59 | }))));
60 | };
61 | exports.ActionPages = ActionPages;
62 | const ResetPassword = _ref2 => {
63 | let {
64 | actionCode
65 | } = _ref2;
66 | const [processing, setProcessing] = (0, _react.useState)(false);
67 | const [error, setError] = (0, _react.useState)(null);
68 | const [stage, setStage] = (0, _react.useState)('verifying');
69 | const {
70 | config
71 | } = (0, _react.useContext)(_Fireact.FireactContext);
72 | const [newPassword, setNewPassword] = (0, _react.useState)('');
73 | const [confirmPassword, setConfirmPassword] = (0, _react.useState)('');
74 | (0, _react.useEffect)(() => {
75 | const auth = (0, _auth.getAuth)();
76 | (0, _auth.verifyPasswordResetCode)(auth, actionCode).then(() => {
77 | setStage('form');
78 | }).catch(error => {
79 | setStage('');
80 | setError(error.message);
81 | });
82 | }, [actionCode]);
83 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, error && /*#__PURE__*/_react.default.createElement(_material.Alert, {
84 | severity: "error"
85 | }, error), stage === 'verifying' && /*#__PURE__*/_react.default.createElement(_material.Typography, null, "Please wait while verifying your request..."), stage === 'form' && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.TextField, {
86 | required: true,
87 | fullWidth: true,
88 | name: "newPassword",
89 | label: "New Password",
90 | type: "password",
91 | autoComplete: "new-password",
92 | margin: "normal",
93 | onChange: e => setNewPassword(e.target.value)
94 | }), /*#__PURE__*/_react.default.createElement(_material.TextField, {
95 | required: true,
96 | fullWidth: true,
97 | name: "confirmPassword",
98 | label: "Confirm Password",
99 | type: "password",
100 | autoComplete: "",
101 | margin: "normal",
102 | onChange: e => setConfirmPassword(e.target.value)
103 | }), /*#__PURE__*/_react.default.createElement(_material.Button, {
104 | type: "button",
105 | fullWidth: true,
106 | variant: "contained",
107 | size: "large",
108 | disabled: processing,
109 | onClick: () => {
110 | setProcessing(true);
111 | setError(null);
112 | const passwordNumericRegex = /\d+/;
113 | const passwordUppercaseRegex = /[A-Z]+/;
114 | const passwordLowercaseRegex = /[a-z]+/;
115 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
116 | if (!passwordNumericRegex.test(String(newPassword)) || !passwordUppercaseRegex.test(String(newPassword)) || !passwordLowercaseRegex.test(String(newPassword)) || !passwordSpecialRegex.test(String(newPassword)) || newPassword.length < 8) {
117 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
118 | setProcessing(false);
119 | } else if (newPassword !== confirmPassword) {
120 | setError('Confirm password does not match with new password.');
121 | setProcessing(false);
122 | } else {
123 | const auth = (0, _auth.getAuth)();
124 | (0, _auth.confirmPasswordReset)(auth, actionCode, newPassword).then(() => {
125 | setStage('success');
126 | }).catch(error => {
127 | setError(error.message);
128 | setProcessing(false);
129 | });
130 | }
131 | }
132 | }, "Reset Password")), stage === 'success' && /*#__PURE__*/_react.default.createElement(_material.Alert, {
133 | severity: "success"
134 | }, "Your email is verified. Please ", /*#__PURE__*/_react.default.createElement(_reactRouterDom.NavLink, {
135 | to: config.pathnames.SignIn
136 | }, "sign in"), " with your new password."));
137 | };
138 | const HandleAction = _ref3 => {
139 | let {
140 | mode,
141 | actionCode
142 | } = _ref3;
143 | const [processing, setProcessing] = (0, _react.useState)(false);
144 | const [error, setError] = (0, _react.useState)(null);
145 | const [success, setSuccess] = (0, _react.useState)(false);
146 | const {
147 | config
148 | } = (0, _react.useContext)(_Fireact.FireactContext);
149 | let processingMessage = 'Please wait';
150 | let successMessage = 'Done';
151 | switch (mode) {
152 | case 'verifyEmail':
153 | processingMessage = 'Please wait while verifying your email...';
154 | successMessage = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "Your email is verified. Please ", /*#__PURE__*/_react.default.createElement(_reactRouterDom.NavLink, {
155 | to: config.pathnames.SignIn
156 | }, "sign in"), " again.");
157 | break;
158 | case 'recoverEmail':
159 | processingMessage = 'Please wait while resotring your email...';
160 | successMessage = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "Your email is restored. Please ", /*#__PURE__*/_react.default.createElement(_reactRouterDom.NavLink, {
161 | to: config.pathnames.ResetPassword
162 | }, "reset password"), " to ensure your account is secured.");
163 | break;
164 | default:
165 | break;
166 | }
167 | (0, _react.useEffect)(() => {
168 | setProcessing(true);
169 | setError(null);
170 | setSuccess(false);
171 | const auth = (0, _auth.getAuth)();
172 | (0, _auth.applyActionCode)(auth, actionCode).then(() => {
173 | setSuccess(true);
174 | setProcessing(false);
175 | }).catch(error => {
176 | setError(error.message);
177 | setProcessing(false);
178 | });
179 | }, [actionCode]);
180 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, processing ? /*#__PURE__*/_react.default.createElement(_material.Typography, null, processingMessage) : success ? /*#__PURE__*/_react.default.createElement(_material.Alert, {
181 | severity: "success"
182 | }, successMessage) : error ? /*#__PURE__*/_react.default.createElement(_material.Alert, {
183 | severity: "error"
184 | }, error) : /*#__PURE__*/_react.default.createElement(_material.Alert, {
185 | severity: "error"
186 | }, "Something went wrong"));
187 | };
--------------------------------------------------------------------------------
/dist/cjs/components/auth/ResetPassword.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.ResetPassword = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | var _react = _interopRequireWildcard(require("react"));
10 | var _material = require("@mui/material");
11 | var _reactRouterDom = require("react-router-dom");
12 | var _auth = require("firebase/auth");
13 | var _SetPageTitle = require("../SetPageTitle");
14 | var _Fireact = require("../Fireact");
15 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
16 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17 | const ResetPassword = _ref => {
18 | let {
19 | logo
20 | } = _ref;
21 | const {
22 | config
23 | } = (0, _react.useContext)(_Fireact.FireactContext);
24 | const pathnames = config.pathnames;
25 | const signInUrl = pathnames.SignIn;
26 | const title = "Reset Password";
27 | const [error, setError] = (0, _react.useState)(null);
28 | const [success, setSuccess] = (0, _react.useState)(false);
29 | const [processing, setProcessing] = (0, _react.useState)(false);
30 | const [email, setEmail] = (0, _react.useState)("");
31 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
32 | title: title
33 | }), logo, /*#__PURE__*/_react.default.createElement(_material.Typography, {
34 | component: "h1",
35 | variant: "h5"
36 | }, title)), /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_material.Stack, {
37 | spacing: 2,
38 | mt: 2
39 | }, error !== null && /*#__PURE__*/_react.default.createElement(_material.Alert, {
40 | severity: "error"
41 | }, error), success && /*#__PURE__*/_react.default.createElement(_material.Alert, {
42 | severity: "success"
43 | }, "A password reset email has been sent to the email address."), /*#__PURE__*/_react.default.createElement(_material.TextField, {
44 | required: true,
45 | fullWidth: true,
46 | name: "email",
47 | label: "Email",
48 | type: "email",
49 | autoComplete: "email",
50 | margin: "normal",
51 | onChange: e => setEmail(e.target.value)
52 | }), /*#__PURE__*/_react.default.createElement(_material.Button, {
53 | type: "button",
54 | fullWidth: true,
55 | variant: "contained",
56 | size: "large",
57 | disabled: processing,
58 | onClick: () => {
59 | setProcessing(true);
60 | setSuccess(false);
61 | setError(null);
62 | const auth = (0, _auth.getAuth)();
63 | (0, _auth.sendPasswordResetEmail)(auth, email).then(() => {
64 | setProcessing(false);
65 | setSuccess(true);
66 | }).catch(error => {
67 | switch (error.code) {
68 | case "auth/invalid-email":
69 | setError('The email address is badly formatted.');
70 | break;
71 | case "auth/missing-email":
72 | setError('The email address is missing.');
73 | break;
74 | case "auth/user-not-found":
75 | setError('There is no user record corresponding to this identifier. The user may have been deleted.');
76 | break;
77 | case "auth/too-many-requests":
78 | setError('We have blocked all requests from this device due to unusual activity. Try again later.');
79 | break;
80 | default:
81 | setError(error.message);
82 | break;
83 | }
84 | setProcessing(false);
85 | });
86 | }
87 | }, "Reset Password"), signInUrl && /*#__PURE__*/_react.default.createElement(_material.Grid, {
88 | container: true
89 | }, signInUrl && /*#__PURE__*/_react.default.createElement(_material.Grid, {
90 | item: true,
91 | xs: true,
92 | textAlign: "left"
93 | }, /*#__PURE__*/_react.default.createElement(_material.Link, {
94 | to: signInUrl,
95 | component: _reactRouterDom.Link
96 | }, "Sign in with an existing account"))))));
97 | };
98 | exports.ResetPassword = ResetPassword;
--------------------------------------------------------------------------------
/dist/cjs/components/auth/SignUp.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.SignUp = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | require("core-js/modules/es.string.trim.js");
10 | require("core-js/modules/es.regexp.exec.js");
11 | require("core-js/modules/es.regexp.test.js");
12 | var _react = _interopRequireWildcard(require("react"));
13 | var _material = require("@mui/material");
14 | var _auth = require("firebase/auth");
15 | var _reactRouterDom = require("react-router-dom");
16 | var _SetPageTitle = require("../SetPageTitle");
17 | var _Fireact = require("../Fireact");
18 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
19 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20 | const SignUp = _ref => {
21 | let {
22 | logo,
23 | successUrl
24 | } = _ref;
25 | const {
26 | config
27 | } = (0, _react.useContext)(_Fireact.FireactContext);
28 | const pathnames = config.pathnames;
29 | const title = "Sign Up";
30 | const signInUrl = pathnames.SignIn;
31 | const resetPasswordUrl = pathnames.ResetPassword;
32 | const re = successUrl || "/"; // redirect successUrl or homepage after sign in
33 |
34 | const [error, setError] = (0, _react.useState)(null);
35 | const [processing, setProcessing] = (0, _react.useState)(false);
36 | const [email, setEmail] = (0, _react.useState)("");
37 | const [fullname, setFullname] = (0, _react.useState)("");
38 | const [password, setPassword] = (0, _react.useState)("");
39 | return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
40 | title: title
41 | }), logo, /*#__PURE__*/_react.default.createElement(_material.Typography, {
42 | component: "h1",
43 | variant: "h5"
44 | }, title)), /*#__PURE__*/_react.default.createElement(_material.Box, null, /*#__PURE__*/_react.default.createElement(_material.Stack, {
45 | spacing: 2,
46 | mt: 2
47 | }, error !== null && /*#__PURE__*/_react.default.createElement(_material.Alert, {
48 | severity: "error"
49 | }, error), /*#__PURE__*/_react.default.createElement(_material.TextField, {
50 | required: true,
51 | fullWidth: true,
52 | name: "email",
53 | label: "Email",
54 | type: "email",
55 | autoComplete: "email",
56 | margin: "normal",
57 | onChange: e => setEmail(e.target.value)
58 | }), /*#__PURE__*/_react.default.createElement(_material.TextField, {
59 | required: true,
60 | fullWidth: true,
61 | name: "fullname",
62 | label: "Full Name",
63 | autoComplete: "name",
64 | type: "text",
65 | margin: "normal",
66 | onChange: e => setFullname(e.target.value)
67 | }), /*#__PURE__*/_react.default.createElement(_material.TextField, {
68 | required: true,
69 | fullWidth: true,
70 | name: "password",
71 | label: "New Password",
72 | autoComplete: "new-password",
73 | type: "password",
74 | margin: "normal",
75 | onChange: e => setPassword(e.target.value)
76 | }), /*#__PURE__*/_react.default.createElement(_material.Button, {
77 | type: "button",
78 | fullWidth: true,
79 | variant: "contained",
80 | size: "large",
81 | disabled: processing,
82 | onClick: () => {
83 | setProcessing(true);
84 | setError(null);
85 | const passwordNumericRegex = /\d+/;
86 | const passwordUppercaseRegex = /[A-Z]+/;
87 | const passwordLowercaseRegex = /[a-z]+/;
88 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
89 | if (fullname.trim() === "") {
90 | setError('Your full name is required.');
91 | setProcessing(false);
92 | } else if (!passwordNumericRegex.test(String(password)) || !passwordUppercaseRegex.test(String(password)) || !passwordLowercaseRegex.test(String(password)) || !passwordSpecialRegex.test(String(password)) || password.length < 8) {
93 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
94 | setProcessing(false);
95 | } else {
96 | const auth = (0, _auth.getAuth)();
97 | (0, _auth.createUserWithEmailAndPassword)(auth, email, password).then(result => {
98 | return (0, _auth.updateProfile)(result.user, {
99 | displayName: fullname
100 | });
101 | }).then(() => {
102 | document.location.href = re.substr(0, 1) === '/' && re.substr(1, 1) !== '/' ? re : '/';
103 | }).catch(error => {
104 | switch (error.code) {
105 | case "auth/invalid-email":
106 | setError('The email address is badly formatted.');
107 | break;
108 | case "auth/missing-email":
109 | setError('The email address is missing.');
110 | break;
111 | case "auth/email-already-in-use":
112 | setError('The email address is already in use by another account.');
113 | break;
114 | default:
115 | setError(error.message);
116 | break;
117 | }
118 | setProcessing(false);
119 | });
120 | }
121 | }
122 | }, "Sign Up"), (signInUrl || resetPasswordUrl) && /*#__PURE__*/_react.default.createElement(_material.Grid, {
123 | container: true
124 | }, signInUrl && /*#__PURE__*/_react.default.createElement(_material.Grid, {
125 | item: true,
126 | xs: true,
127 | textAlign: "left"
128 | }, /*#__PURE__*/_react.default.createElement(_material.Link, {
129 | to: signInUrl,
130 | component: _reactRouterDom.Link
131 | }, "Sign in with an existing account")), resetPasswordUrl && /*#__PURE__*/_react.default.createElement(_material.Grid, {
132 | item: true,
133 | textAlign: "left"
134 | }, /*#__PURE__*/_react.default.createElement(_material.Link, {
135 | to: resetPasswordUrl,
136 | component: _reactRouterDom.Link
137 | }, "Reset password"))))));
138 | };
139 | exports.SignUp = SignUp;
--------------------------------------------------------------------------------
/dist/cjs/components/menus/MainMenu.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | require("core-js/modules/web.dom-collections.iterator.js");
5 | Object.defineProperty(exports, "__esModule", {
6 | value: true
7 | });
8 | exports.MainMenu = void 0;
9 | var _material = require("@mui/material");
10 | var _react = _interopRequireWildcard(require("react"));
11 | var _reactRouterDom = require("react-router-dom");
12 | var _Home = _interopRequireDefault(require("@mui/icons-material/Home"));
13 | var _AccountBox = _interopRequireDefault(require("@mui/icons-material/AccountBox"));
14 | var _Fireact = require("../Fireact");
15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
17 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
18 | const MainMenu = _ref => {
19 | let {
20 | customItems
21 | } = _ref;
22 | const {
23 | config
24 | } = (0, _react.useContext)(_Fireact.FireactContext);
25 | const pathnames = config.pathnames;
26 | const profileUrl = pathnames.UserProfile;
27 | return /*#__PURE__*/_react.default.createElement(_material.List, {
28 | component: "nav"
29 | }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.NavLink, {
30 | to: "/",
31 | style: {
32 | textDecoration: 'none'
33 | },
34 | key: "home"
35 | }, /*#__PURE__*/_react.default.createElement(_material.ListItemButton, null, /*#__PURE__*/_react.default.createElement(_material.ListItemIcon, null, /*#__PURE__*/_react.default.createElement(_Home.default, null)), /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
36 | primary: /*#__PURE__*/_react.default.createElement(_material.Typography, {
37 | color: "textPrimary"
38 | }, "Home")
39 | }))), customItems, profileUrl && [/*#__PURE__*/_react.default.createElement(_material.Divider, {
40 | key: "profile-divider"
41 | }), /*#__PURE__*/_react.default.createElement(_reactRouterDom.NavLink, {
42 | to: profileUrl,
43 | style: {
44 | textDecoration: 'none'
45 | },
46 | key: "profile"
47 | }, /*#__PURE__*/_react.default.createElement(_material.ListItemButton, null, /*#__PURE__*/_react.default.createElement(_material.ListItemIcon, null, /*#__PURE__*/_react.default.createElement(_AccountBox.default, null)), /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
48 | primary: /*#__PURE__*/_react.default.createElement(_material.Typography, {
49 | color: "textPrimary"
50 | }, "My Profile")
51 | })))]);
52 | };
53 | exports.MainMenu = MainMenu;
--------------------------------------------------------------------------------
/dist/cjs/components/menus/UserMenu.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.UserMenu = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | var _material = require("@mui/material");
10 | var _react = _interopRequireWildcard(require("react"));
11 | var _Auth = require("../Auth");
12 | var _AccountBox = _interopRequireDefault(require("@mui/icons-material/AccountBox"));
13 | var _ExitToApp = _interopRequireDefault(require("@mui/icons-material/ExitToApp"));
14 | var _auth = require("firebase/auth");
15 | var _reactRouterDom = require("react-router-dom");
16 | var _Fireact = require("../Fireact");
17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
19 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
20 | const UserMenu = _ref => {
21 | let {
22 | customItems
23 | } = _ref;
24 | const {
25 | config
26 | } = (0, _react.useContext)(_Fireact.FireactContext);
27 | const pathnames = config.pathnames;
28 | const profileUrl = pathnames.UserProfile;
29 | const [anchorEl, setAnchorEl] = (0, _react.useState)(null);
30 | const open = Boolean(anchorEl);
31 | const handleMenu = event => {
32 | setAnchorEl(event.currentTarget);
33 | };
34 | const handleClose = () => {
35 | setAnchorEl(null);
36 | };
37 | const navigate = (0, _reactRouterDom.useNavigate)();
38 | return /*#__PURE__*/_react.default.createElement(_Auth.AuthContext.Consumer, null, context => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
39 | "ria-label": "account of current user",
40 | "aria-controls": "menu-appbar",
41 | onClick: handleMenu,
42 | "aria-haspopup": "true"
43 | }, /*#__PURE__*/_react.default.createElement(_material.Avatar, {
44 | alt: context.authUser.user.displayName,
45 | src: context.authUser.user.photoURL ? context.authUser.user.photoURL : "https://ui-avatars.com/api/?name=" + encodeURI(context.authUser.user.displayName) + "&background=007bff&size=64&color=f8f9fc"
46 | })), /*#__PURE__*/_react.default.createElement(_material.Menu, {
47 | id: "menu-appbar",
48 | anchorEl: anchorEl,
49 | anchorOrigin: {
50 | vertical: 'bottom',
51 | horizontal: 'right'
52 | },
53 | keepMounted: true,
54 | transformOrigin: {
55 | vertical: 'top',
56 | horizontal: 'right'
57 | },
58 | open: open,
59 | onClose: handleClose
60 | }, profileUrl && [/*#__PURE__*/_react.default.createElement(_material.MenuItem, {
61 | key: "profile-menu-item",
62 | onClick: e => {
63 | e.preventDefault();
64 | handleClose();
65 | navigate(profileUrl);
66 | }
67 | }, /*#__PURE__*/_react.default.createElement(_AccountBox.default, {
68 | sx: {
69 | marginRight: "10px"
70 | }
71 | }), " Profile"), /*#__PURE__*/_react.default.createElement(_material.Divider, {
72 | key: "profile-menu-divider"
73 | })], customItems, /*#__PURE__*/_react.default.createElement(_material.MenuItem, {
74 | onClick: e => {
75 | e.preventDefault();
76 | handleClose();
77 | const auth = (0, _auth.getAuth)();
78 | (0, _auth.signOut)(auth).then(() => {
79 | document.location.href = "/";
80 | });
81 | }
82 | }, /*#__PURE__*/_react.default.createElement(_ExitToApp.default, {
83 | sx: {
84 | marginRight: "10px"
85 | }
86 | }), " Sign Out"))));
87 | };
88 | exports.UserMenu = UserMenu;
--------------------------------------------------------------------------------
/dist/cjs/components/templates/AppTemplate.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.AppTemplate = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | require("core-js/modules/es.symbol.description.js");
10 | var _react = _interopRequireWildcard(require("react"));
11 | var _styles = require("@mui/material/styles");
12 | var _material = require("@mui/material");
13 | var _Menu = _interopRequireDefault(require("@mui/icons-material/Menu"));
14 | var _ChevronLeft = _interopRequireDefault(require("@mui/icons-material/ChevronLeft"));
15 | var _ChevronRight = _interopRequireDefault(require("@mui/icons-material/ChevronRight"));
16 | var _reactRouterDom = require("react-router-dom");
17 | var _Fireact = require("../Fireact");
18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
20 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
21 | function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
22 | function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
23 | function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
24 | function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
25 | function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
26 | const drawerWidth = 240;
27 | const openedMixin = theme => ({
28 | width: drawerWidth,
29 | transition: theme.transitions.create('width', {
30 | easing: theme.transitions.easing.sharp,
31 | duration: theme.transitions.duration.enteringScreen
32 | }),
33 | overflowX: 'hidden'
34 | });
35 | const closedMixin = theme => ({
36 | transition: theme.transitions.create('width', {
37 | easing: theme.transitions.easing.sharp,
38 | duration: theme.transitions.duration.leavingScreen
39 | }),
40 | overflowX: 'hidden',
41 | width: "calc(".concat(theme.spacing(7), " + 1px)"),
42 | [theme.breakpoints.up('sm')]: {
43 | width: "calc(".concat(theme.spacing(9), " + 1px)")
44 | }
45 | });
46 | const DrawerHeader = (0, _styles.styled)('div')(_ref => {
47 | let {
48 | theme
49 | } = _ref;
50 | return _objectSpread({
51 | display: 'flex',
52 | alignItems: 'center',
53 | justifyContent: 'flex-end',
54 | padding: theme.spacing(0, 1)
55 | }, theme.mixins.toolbar);
56 | });
57 | const AppBar = (0, _styles.styled)(_material.AppBar, {
58 | shouldForwardProp: prop => prop !== 'open'
59 | })(_ref2 => {
60 | let {
61 | theme,
62 | open
63 | } = _ref2;
64 | return _objectSpread({
65 | zIndex: theme.zIndex.drawer + 1,
66 | transition: theme.transitions.create(['width', 'margin'], {
67 | easing: theme.transitions.easing.sharp,
68 | duration: theme.transitions.duration.leavingScreen
69 | })
70 | }, open && {
71 | marginLeft: drawerWidth,
72 | width: "calc(100% - ".concat(drawerWidth, "px)"),
73 | transition: theme.transitions.create(['width', 'margin'], {
74 | easing: theme.transitions.easing.sharp,
75 | duration: theme.transitions.duration.enteringScreen
76 | })
77 | });
78 | });
79 | const Drawer = (0, _styles.styled)(_material.Drawer, {
80 | shouldForwardProp: prop => prop !== 'open'
81 | })(_ref3 => {
82 | let {
83 | theme,
84 | open
85 | } = _ref3;
86 | return _objectSpread(_objectSpread({
87 | width: drawerWidth,
88 | flexShrink: 0,
89 | whiteSpace: 'nowrap',
90 | boxSizing: 'border-box'
91 | }, open && _objectSpread(_objectSpread({}, openedMixin(theme)), {}, {
92 | '& .MuiDrawer-paper': openedMixin(theme)
93 | })), !open && _objectSpread(_objectSpread({}, closedMixin(theme)), {}, {
94 | '& .MuiDrawer-paper': closedMixin(theme)
95 | }));
96 | });
97 | const AppTemplate = _ref4 => {
98 | let {
99 | logo,
100 | drawerMenu,
101 | toolbarChildren,
102 | toolBarMenu
103 | } = _ref4;
104 | const theme = (0, _styles.useTheme)();
105 | const [open, setOpen] = (0, _react.useState)(true);
106 | const handleDrawerOpen = () => {
107 | setOpen(true);
108 | };
109 | const handleDrawerClose = () => {
110 | setOpen(false);
111 | };
112 | const {
113 | config
114 | } = (0, _react.useContext)(_Fireact.FireactContext);
115 | const brand = config.brand;
116 | const navigate = (0, _reactRouterDom.useNavigate)();
117 | return /*#__PURE__*/_react.default.createElement(_material.Box, {
118 | sx: {
119 | display: "flex"
120 | }
121 | }, /*#__PURE__*/_react.default.createElement(_material.CssBaseline, null), /*#__PURE__*/_react.default.createElement(AppBar, {
122 | position: "fixed",
123 | open: open
124 | }, /*#__PURE__*/_react.default.createElement(_material.Toolbar, null, /*#__PURE__*/_react.default.createElement(_material.IconButton, {
125 | color: "inherit",
126 | "aria-label": "open drawer",
127 | onClick: handleDrawerOpen,
128 | edge: "start",
129 | sx: _objectSpread({
130 | marginRight: '36px'
131 | }, open && {
132 | display: 'none'
133 | })
134 | }, /*#__PURE__*/_react.default.createElement(_Menu.default, null)), toolbarChildren, /*#__PURE__*/_react.default.createElement("div", {
135 | style: {
136 | marginLeft: "auto",
137 | marginRight: "0px"
138 | }
139 | }, toolBarMenu))), /*#__PURE__*/_react.default.createElement(Drawer, {
140 | variant: "permanent",
141 | open: open
142 | }, /*#__PURE__*/_react.default.createElement(DrawerHeader, null, open && /*#__PURE__*/_react.default.createElement("div", {
143 | style: {
144 | marginLeft: '0px',
145 | marginRight: 'auto',
146 | display: 'inline-flex',
147 | alignItems: 'center',
148 | flexWrap: 'wrap'
149 | }
150 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
151 | style: {
152 | color: "#000000"
153 | },
154 | onClick: () => navigate("/")
155 | }, /*#__PURE__*/_react.default.createElement("div", {
156 | style: {
157 | display: 'inline-flex',
158 | paddingRight: '20px'
159 | }
160 | }, logo), /*#__PURE__*/_react.default.createElement(_material.Typography, {
161 | variant: "h6"
162 | }, brand))), /*#__PURE__*/_react.default.createElement(_material.IconButton, {
163 | onClick: handleDrawerClose
164 | }, theme.direction === 'rtl' ? /*#__PURE__*/_react.default.createElement(_ChevronRight.default, null) : /*#__PURE__*/_react.default.createElement(_ChevronLeft.default, null))), /*#__PURE__*/_react.default.createElement(_material.Divider, null), drawerMenu, /*#__PURE__*/_react.default.createElement(_material.Divider, null)), /*#__PURE__*/_react.default.createElement(_material.Box, {
165 | component: "main",
166 | sx: {
167 | flexGrow: 1,
168 | backgroundColor: theme => theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900],
169 | height: '100vh',
170 | overflow: 'auto'
171 | }
172 | }, /*#__PURE__*/_react.default.createElement(DrawerHeader, null), /*#__PURE__*/_react.default.createElement("div", {
173 | style: {
174 | position: 'relative'
175 | }
176 | }, /*#__PURE__*/_react.default.createElement(_material.Box, {
177 | mt: 5,
178 | ml: 3,
179 | mr: 3,
180 | mb: 3
181 | }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Outlet, null)))));
182 | };
183 | exports.AppTemplate = AppTemplate;
--------------------------------------------------------------------------------
/dist/cjs/components/templates/PublicTemplate.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.PublicTemplate = void 0;
7 | var _react = _interopRequireDefault(require("react"));
8 | var _material = require("@mui/material");
9 | var _reactRouterDom = require("react-router-dom");
10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11 | const PublicTemplate = () => {
12 | return /*#__PURE__*/_react.default.createElement(_material.Box, {
13 | mt: 10
14 | }, /*#__PURE__*/_react.default.createElement(_material.Container, {
15 | maxWidth: "sm"
16 | }, /*#__PURE__*/_react.default.createElement(_material.Box, {
17 | component: "span",
18 | m: 5,
19 | textAlign: "center"
20 | }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Outlet, null))));
21 | };
22 | exports.PublicTemplate = PublicTemplate;
--------------------------------------------------------------------------------
/dist/cjs/components/user/UserDelete.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.UserDelete = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | var _material = require("@mui/material");
10 | var _react = _interopRequireWildcard(require("react"));
11 | var _reactRouterDom = require("react-router-dom");
12 | var _SetPageTitle = require("../SetPageTitle");
13 | var _auth = require("firebase/auth");
14 | var _Fireact = require("../Fireact");
15 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
16 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17 | const UserDelete = () => {
18 | const [email, setEmail] = (0, _react.useState)("");
19 | const [error, setError] = (0, _react.useState)(null);
20 | const [processing, setProcessing] = (0, _react.useState)(false);
21 | const title = "Delete Account";
22 | const navigate = (0, _reactRouterDom.useNavigate)();
23 | const auth = (0, _auth.getAuth)();
24 | const {
25 | config
26 | } = (0, _react.useContext)(_Fireact.FireactContext);
27 | const pathnames = config.pathnames;
28 | return /*#__PURE__*/_react.default.createElement(_material.Container, {
29 | maxWidth: "md"
30 | }, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
31 | title: title
32 | }), /*#__PURE__*/_react.default.createElement(_material.Paper, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
33 | p: 2
34 | }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
35 | component: "h1",
36 | variant: "h4",
37 | align: "center"
38 | }, title)), error !== null && /*#__PURE__*/_react.default.createElement(_material.Box, {
39 | p: 2
40 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
41 | severity: "error"
42 | }, error)), /*#__PURE__*/_react.default.createElement(_material.Box, {
43 | p: 2
44 | }, /*#__PURE__*/_react.default.createElement(_material.Typography, null, "Please confirm your email address to delete your user account."), /*#__PURE__*/_react.default.createElement(_material.TextField, {
45 | required: true,
46 | fullWidth: true,
47 | name: "email",
48 | label: "Email Address",
49 | type: "email",
50 | autoComplete: "email",
51 | margin: "normal",
52 | onChange: e => setEmail(e.target.value)
53 | })), /*#__PURE__*/_react.default.createElement(_material.Box, {
54 | p: 2
55 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
56 | container: true
57 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
58 | item: true,
59 | xs: true
60 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
61 | type: "button",
62 | color: "secondary",
63 | variant: "outlined",
64 | disabled: processing,
65 | onClick: () => {
66 | navigate(pathnames.UserProfile);
67 | }
68 | }, "Back")), /*#__PURE__*/_react.default.createElement(_material.Grid, {
69 | item: true
70 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
71 | type: "button",
72 | color: "error",
73 | variant: "contained",
74 | disabled: processing,
75 | onClick: () => {
76 | setProcessing(true);
77 | setError(null);
78 | if (auth.currentUser.email !== email) {
79 | setError("The email address does not match with your email address.");
80 | setProcessing(false);
81 | } else {
82 | (0, _auth.deleteUser)(auth.currentUser).then(() => {
83 | // refresh page
84 | document.location.href = "/";
85 | }).catch(error => {
86 | switch (error.code) {
87 | case "auth/requires-recent-login":
88 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
89 | break;
90 | default:
91 | setError(error.message);
92 | break;
93 | }
94 | setProcessing(false);
95 | });
96 | }
97 | }
98 | }, "Delete User Account"))))));
99 | };
100 | exports.UserDelete = UserDelete;
--------------------------------------------------------------------------------
/dist/cjs/components/user/UserUpdateEmail.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.UserUpdateEmail = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | var _material = require("@mui/material");
10 | var _react = _interopRequireWildcard(require("react"));
11 | var _reactRouterDom = require("react-router-dom");
12 | var _SetPageTitle = require("../SetPageTitle");
13 | var _auth = require("firebase/auth");
14 | var _Fireact = require("../Fireact");
15 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
16 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
17 | const UserUpdateEmail = () => {
18 | const [email, setEmail] = (0, _react.useState)("");
19 | const [error, setError] = (0, _react.useState)(null);
20 | const [success, setSuccess] = (0, _react.useState)(false);
21 | const [processing, setProcessing] = (0, _react.useState)(false);
22 | const title = "Change Email";
23 | const navigate = (0, _reactRouterDom.useNavigate)();
24 | const auth = (0, _auth.getAuth)();
25 | const {
26 | config
27 | } = (0, _react.useContext)(_Fireact.FireactContext);
28 | const pathnames = config.pathnames;
29 | return /*#__PURE__*/_react.default.createElement(_material.Container, {
30 | maxWidth: "md"
31 | }, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
32 | title: title
33 | }), /*#__PURE__*/_react.default.createElement(_material.Paper, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
34 | p: 2
35 | }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
36 | component: "h1",
37 | variant: "h4",
38 | align: "center"
39 | }, title)), error !== null && /*#__PURE__*/_react.default.createElement(_material.Box, {
40 | p: 2
41 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
42 | severity: "error"
43 | }, error)), success && /*#__PURE__*/_react.default.createElement(_material.Box, {
44 | p: 2
45 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
46 | severity: "success"
47 | }, "Your email address has been updated successfully.")), /*#__PURE__*/_react.default.createElement(_material.Box, {
48 | p: 2
49 | }, /*#__PURE__*/_react.default.createElement(_material.TextField, {
50 | required: true,
51 | fullWidth: true,
52 | name: "email",
53 | label: "New Email Address",
54 | type: "email",
55 | autoComplete: "email",
56 | margin: "normal",
57 | onChange: e => setEmail(e.target.value)
58 | })), /*#__PURE__*/_react.default.createElement(_material.Box, {
59 | p: 2
60 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
61 | container: true
62 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
63 | item: true,
64 | xs: true
65 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
66 | type: "button",
67 | color: "secondary",
68 | variant: "outlined",
69 | disabled: processing,
70 | onClick: () => {
71 | navigate(pathnames.UserProfile);
72 | }
73 | }, "Back")), /*#__PURE__*/_react.default.createElement(_material.Grid, {
74 | item: true
75 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
76 | type: "button",
77 | variant: "contained",
78 | disabled: processing,
79 | onClick: () => {
80 | setProcessing(true);
81 | setSuccess(false);
82 | setError(null);
83 | (0, _auth.updateEmail)(auth.currentUser, email).then(() => {
84 | setSuccess(true);
85 | setProcessing(false);
86 | }).catch(error => {
87 | switch (error.code) {
88 | case "auth/requires-recent-login":
89 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
90 | break;
91 | case "auth/email-already-in-use":
92 | setError("The email address is already in use by another account.");
93 | break;
94 | default:
95 | setError(error.message);
96 | break;
97 | }
98 | setProcessing(false);
99 | });
100 | }
101 | }, "Save"))))));
102 | };
103 | exports.UserUpdateEmail = UserUpdateEmail;
--------------------------------------------------------------------------------
/dist/cjs/components/user/UserUpdateName.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.UserUpdateName = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | require("core-js/modules/es.string.trim.js");
10 | var _material = require("@mui/material");
11 | var _react = _interopRequireWildcard(require("react"));
12 | var _reactRouterDom = require("react-router-dom");
13 | var _SetPageTitle = require("../SetPageTitle");
14 | var _auth = require("firebase/auth");
15 | var _Fireact = require("../Fireact");
16 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
17 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
18 | const UserUpdateName = () => {
19 | const [fullname, setFullname] = (0, _react.useState)("");
20 | const [error, setError] = (0, _react.useState)(null);
21 | const [success, setSuccess] = (0, _react.useState)(false);
22 | const [processing, setProcessing] = (0, _react.useState)(false);
23 | const title = "Change Name";
24 | const navigate = (0, _reactRouterDom.useNavigate)();
25 | const auth = (0, _auth.getAuth)();
26 | const {
27 | config
28 | } = (0, _react.useContext)(_Fireact.FireactContext);
29 | const pathnames = config.pathnames;
30 | return /*#__PURE__*/_react.default.createElement(_material.Container, {
31 | maxWidth: "md"
32 | }, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
33 | title: title
34 | }), /*#__PURE__*/_react.default.createElement(_material.Paper, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
35 | p: 2
36 | }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
37 | component: "h1",
38 | variant: "h4",
39 | align: "center"
40 | }, title)), error !== null && /*#__PURE__*/_react.default.createElement(_material.Box, {
41 | p: 2
42 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
43 | severity: "error"
44 | }, error)), success && /*#__PURE__*/_react.default.createElement(_material.Box, {
45 | p: 2
46 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
47 | severity: "success"
48 | }, "Your name has been updated successfully.")), /*#__PURE__*/_react.default.createElement(_material.Box, {
49 | p: 2
50 | }, /*#__PURE__*/_react.default.createElement(_material.TextField, {
51 | required: true,
52 | fullWidth: true,
53 | name: "fullname",
54 | label: "Full Name",
55 | autoComplete: "name",
56 | type: "text",
57 | margin: "normal",
58 | onChange: e => setFullname(e.target.value)
59 | })), /*#__PURE__*/_react.default.createElement(_material.Box, {
60 | p: 2
61 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
62 | container: true
63 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
64 | item: true,
65 | xs: true
66 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
67 | type: "button",
68 | color: "secondary",
69 | variant: "outlined",
70 | disabled: processing,
71 | onClick: () => {
72 | navigate(pathnames.UserProfile);
73 | }
74 | }, "Back")), /*#__PURE__*/_react.default.createElement(_material.Grid, {
75 | item: true
76 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
77 | type: "button",
78 | variant: "contained",
79 | disabled: processing,
80 | onClick: () => {
81 | setProcessing(true);
82 | setSuccess(false);
83 | setError(null);
84 | if (fullname.trim() === "") {
85 | setError('Your full name is required.');
86 | setProcessing(false);
87 | } else {
88 | (0, _auth.updateProfile)(auth.currentUser, {
89 | displayName: fullname
90 | }).then(() => {
91 | setSuccess(true);
92 | setProcessing(false);
93 | }).catch(error => {
94 | switch (error.code) {
95 | case "auth/requires-recent-login":
96 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
97 | break;
98 | default:
99 | setError(error.message);
100 | break;
101 | }
102 | setProcessing(false);
103 | });
104 | }
105 | }
106 | }, "Save"))))));
107 | };
108 | exports.UserUpdateName = UserUpdateName;
--------------------------------------------------------------------------------
/dist/cjs/components/user/UserUpdatePassword.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("core-js/modules/es.weak-map.js");
4 | Object.defineProperty(exports, "__esModule", {
5 | value: true
6 | });
7 | exports.UserUpdatePassword = void 0;
8 | require("core-js/modules/web.dom-collections.iterator.js");
9 | require("core-js/modules/es.regexp.exec.js");
10 | require("core-js/modules/es.regexp.test.js");
11 | var _material = require("@mui/material");
12 | var _react = _interopRequireWildcard(require("react"));
13 | var _reactRouterDom = require("react-router-dom");
14 | var _SetPageTitle = require("../SetPageTitle");
15 | var _auth = require("firebase/auth");
16 | var _Fireact = require("../Fireact");
17 | function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
18 | function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
19 | const UserUpdatePassword = () => {
20 | const [password, setPassword] = (0, _react.useState)("");
21 | const [error, setError] = (0, _react.useState)(null);
22 | const [success, setSuccess] = (0, _react.useState)(false);
23 | const [processing, setProcessing] = (0, _react.useState)(false);
24 | const title = "Change Password";
25 | const navigate = (0, _reactRouterDom.useNavigate)();
26 | const auth = (0, _auth.getAuth)();
27 | const {
28 | config
29 | } = (0, _react.useContext)(_Fireact.FireactContext);
30 | const pathnames = config.pathnames;
31 | return /*#__PURE__*/_react.default.createElement(_material.Container, {
32 | maxWidth: "md"
33 | }, /*#__PURE__*/_react.default.createElement(_SetPageTitle.SetPageTitle, {
34 | title: title
35 | }), /*#__PURE__*/_react.default.createElement(_material.Paper, null, /*#__PURE__*/_react.default.createElement(_material.Box, {
36 | p: 2
37 | }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
38 | component: "h1",
39 | variant: "h4",
40 | align: "center"
41 | }, title)), error !== null && /*#__PURE__*/_react.default.createElement(_material.Box, {
42 | p: 2
43 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
44 | severity: "error"
45 | }, error)), success && /*#__PURE__*/_react.default.createElement(_material.Box, {
46 | p: 2
47 | }, /*#__PURE__*/_react.default.createElement(_material.Alert, {
48 | severity: "success"
49 | }, "Your password has been updated successfully.")), /*#__PURE__*/_react.default.createElement(_material.Box, {
50 | p: 2
51 | }, /*#__PURE__*/_react.default.createElement(_material.TextField, {
52 | required: true,
53 | fullWidth: true,
54 | name: "password",
55 | label: "New Password",
56 | autoComplete: "new-password",
57 | type: "password",
58 | margin: "normal",
59 | onChange: e => setPassword(e.target.value)
60 | })), /*#__PURE__*/_react.default.createElement(_material.Box, {
61 | p: 2
62 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
63 | container: true
64 | }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
65 | item: true,
66 | xs: true
67 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
68 | type: "button",
69 | color: "secondary",
70 | variant: "outlined",
71 | disabled: processing,
72 | onClick: () => {
73 | navigate(pathnames.UserProfile);
74 | }
75 | }, "Back")), /*#__PURE__*/_react.default.createElement(_material.Grid, {
76 | item: true
77 | }, /*#__PURE__*/_react.default.createElement(_material.Button, {
78 | type: "button",
79 | variant: "contained",
80 | disabled: processing,
81 | onClick: () => {
82 | const passwordNumericRegex = /\d+/;
83 | const passwordUppercaseRegex = /[A-Z]+/;
84 | const passwordLowercaseRegex = /[a-z]+/;
85 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
86 | setProcessing(true);
87 | setSuccess(false);
88 | setError(null);
89 | if (!passwordNumericRegex.test(String(password)) || !passwordUppercaseRegex.test(String(password)) || !passwordLowercaseRegex.test(String(password)) || !passwordSpecialRegex.test(String(password)) || password.length < 8) {
90 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
91 | setProcessing(false);
92 | } else {
93 | (0, _auth.updatePassword)(auth.currentUser, password).then(() => {
94 | setSuccess(true);
95 | setProcessing(false);
96 | }).catch(error => {
97 | switch (error.code) {
98 | case "auth/requires-recent-login":
99 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
100 | break;
101 | default:
102 | setError(error.message);
103 | break;
104 | }
105 | setProcessing(false);
106 | });
107 | }
108 | }
109 | }, "Save"))))));
110 | };
111 | exports.UserUpdatePassword = UserUpdatePassword;
--------------------------------------------------------------------------------
/dist/cjs/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | Object.defineProperty(exports, "ActionPages", {
7 | enumerable: true,
8 | get: function get() {
9 | return _ActionPages.ActionPages;
10 | }
11 | });
12 | Object.defineProperty(exports, "AppTemplate", {
13 | enumerable: true,
14 | get: function get() {
15 | return _AppTemplate.AppTemplate;
16 | }
17 | });
18 | Object.defineProperty(exports, "AuthContext", {
19 | enumerable: true,
20 | get: function get() {
21 | return _Auth.AuthContext;
22 | }
23 | });
24 | Object.defineProperty(exports, "AuthProvider", {
25 | enumerable: true,
26 | get: function get() {
27 | return _Auth.AuthProvider;
28 | }
29 | });
30 | Object.defineProperty(exports, "AuthRoutes", {
31 | enumerable: true,
32 | get: function get() {
33 | return _Auth.AuthRoutes;
34 | }
35 | });
36 | Object.defineProperty(exports, "FireactContext", {
37 | enumerable: true,
38 | get: function get() {
39 | return _Fireact.FireactContext;
40 | }
41 | });
42 | Object.defineProperty(exports, "FireactProvider", {
43 | enumerable: true,
44 | get: function get() {
45 | return _Fireact.FireactProvider;
46 | }
47 | });
48 | Object.defineProperty(exports, "MainMenu", {
49 | enumerable: true,
50 | get: function get() {
51 | return _MainMenu.MainMenu;
52 | }
53 | });
54 | Object.defineProperty(exports, "PublicTemplate", {
55 | enumerable: true,
56 | get: function get() {
57 | return _PublicTemplate.PublicTemplate;
58 | }
59 | });
60 | Object.defineProperty(exports, "ResetPassword", {
61 | enumerable: true,
62 | get: function get() {
63 | return _ResetPassword.ResetPassword;
64 | }
65 | });
66 | Object.defineProperty(exports, "SetPageTitle", {
67 | enumerable: true,
68 | get: function get() {
69 | return _SetPageTitle.SetPageTitle;
70 | }
71 | });
72 | Object.defineProperty(exports, "SignIn", {
73 | enumerable: true,
74 | get: function get() {
75 | return _SignIn.SignIn;
76 | }
77 | });
78 | Object.defineProperty(exports, "SignUp", {
79 | enumerable: true,
80 | get: function get() {
81 | return _SignUp.SignUp;
82 | }
83 | });
84 | Object.defineProperty(exports, "UserDelete", {
85 | enumerable: true,
86 | get: function get() {
87 | return _UserDelete.UserDelete;
88 | }
89 | });
90 | Object.defineProperty(exports, "UserMenu", {
91 | enumerable: true,
92 | get: function get() {
93 | return _UserMenu.UserMenu;
94 | }
95 | });
96 | Object.defineProperty(exports, "UserProfile", {
97 | enumerable: true,
98 | get: function get() {
99 | return _UserProfile.UserProfile;
100 | }
101 | });
102 | Object.defineProperty(exports, "UserUpdateEmail", {
103 | enumerable: true,
104 | get: function get() {
105 | return _UserUpdateEmail.UserUpdateEmail;
106 | }
107 | });
108 | Object.defineProperty(exports, "UserUpdateName", {
109 | enumerable: true,
110 | get: function get() {
111 | return _UserUpdateName.UserUpdateName;
112 | }
113 | });
114 | Object.defineProperty(exports, "UserUpdatePassword", {
115 | enumerable: true,
116 | get: function get() {
117 | return _UserUpdatePassword.UserUpdatePassword;
118 | }
119 | });
120 | Object.defineProperty(exports, "pathnames", {
121 | enumerable: true,
122 | get: function get() {
123 | return _pathnames.default;
124 | }
125 | });
126 | var _Auth = require("./components/Auth");
127 | var _UserDelete = require("./components/user/UserDelete");
128 | var _PublicTemplate = require("./components/templates/PublicTemplate");
129 | var _SignIn = require("./components/auth/SignIn");
130 | var _SignUp = require("./components/auth/SignUp");
131 | var _ResetPassword = require("./components/auth/ResetPassword");
132 | var _AppTemplate = require("./components/templates/AppTemplate");
133 | var _UserMenu = require("./components/menus/UserMenu");
134 | var _MainMenu = require("./components/menus/MainMenu");
135 | var _UserProfile = require("./components/user/UserProfile");
136 | var _UserUpdateEmail = require("./components/user/UserUpdateEmail");
137 | var _UserUpdateName = require("./components/user/UserUpdateName");
138 | var _UserUpdatePassword = require("./components/user/UserUpdatePassword");
139 | var _SetPageTitle = require("./components/SetPageTitle");
140 | var _Fireact = require("./components/Fireact");
141 | var _ActionPages = require("./components/auth/ActionPages");
142 | var _pathnames = _interopRequireDefault(require("./pathnames.json"));
143 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
--------------------------------------------------------------------------------
/dist/cjs/pathnames.json:
--------------------------------------------------------------------------------
1 | {
2 | "ActionPages": "/auth-action",
3 | "ResetPassword": "/reset-password",
4 | "SignIn": "/sign-in",
5 | "SignUp": "/sign-up",
6 | "UserDelete": "/user/delete",
7 | "UserProfile": "/user",
8 | "UserUpdateEmail": "/user/update-email",
9 | "UserUpdateName": "/user/update-name",
10 | "UserUpdatePassword": "/user/update-password"
11 | }
--------------------------------------------------------------------------------
/dist/esm/assets/images/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/dist/esm/assets/images/microsoft.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/dist/esm/components/Auth.js:
--------------------------------------------------------------------------------
1 | function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2 | function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3 | function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
4 | function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
5 | function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6 | import "core-js/modules/web.dom-collections.iterator.js";
7 | import "core-js/modules/es.regexp.exec.js";
8 | import "core-js/modules/es.string.search.js";
9 | import "core-js/modules/es.symbol.description.js";
10 | import React, { useEffect, useState, useContext } from "react";
11 | import { initializeApp } from 'firebase/app';
12 | import { getAuth, onAuthStateChanged } from 'firebase/auth';
13 | import { Navigate, Outlet } from "react-router-dom";
14 | import { Box, Container } from "@mui/material";
15 | import { doc, getFirestore, setDoc } from "firebase/firestore";
16 | import { FireactContext } from "./Fireact";
17 | import { getFunctions } from "firebase/functions";
18 | export const AuthContext = /*#__PURE__*/React.createContext();
19 | export const AuthProvider = _ref => {
20 | let {
21 | children
22 | } = _ref;
23 | // authorized user state
24 | const [authUser, setAuthUser] = useState({
25 | user: null,
26 | data: {},
27 | checked: false
28 | });
29 | const {
30 | config
31 | } = useContext(FireactContext);
32 | const [firebaseApp, setFirebaseApp] = useState(null);
33 | const [authInstance, setAuthInstance] = useState(null);
34 | const [firestoreInstance, setFirestoreInstance] = useState(null);
35 | const [functionsInstance, setFunctionsInstance] = useState(null);
36 | useEffect(() => {
37 | const app = initializeApp(config.firebaseConfig);
38 | const auth = getAuth(app);
39 | const firestore = getFirestore(app);
40 | const functions = getFunctions(app);
41 | setFirebaseApp(app);
42 | setAuthInstance(auth);
43 | setFirestoreInstance(firestore);
44 | setFunctionsInstance(functions);
45 | onAuthStateChanged(auth, user => {
46 | if (user !== null) {
47 | user.getIdToken().then(token => {
48 | const userDoc = doc(firestore, 'users', user.uid);
49 | setAuthUser(prevState => _objectSpread(_objectSpread({}, prevState), {}, {
50 | user: user,
51 | checked: true
52 | }));
53 | setDoc(userDoc, {
54 | displayName: user.displayName,
55 | photoURL: user.photoURL,
56 | email: user.email
57 | }, {
58 | merge: true
59 | });
60 | });
61 | } else {
62 | setAuthUser(prevState => _objectSpread(_objectSpread({}, prevState), {}, {
63 | user: null,
64 | checked: true
65 | }));
66 | }
67 | });
68 | }, [config.firebaseConfig]);
69 | return /*#__PURE__*/React.createElement(AuthContext.Provider, {
70 | value: {
71 | authUser,
72 | setAuthUser,
73 | firebaseApp,
74 | authInstance,
75 | firestoreInstance,
76 | functionsInstance
77 | }
78 | }, children);
79 | };
80 | export const AuthRoutes = _ref2 => {
81 | let {
82 | loader
83 | } = _ref2;
84 | const {
85 | authUser
86 | } = useContext(AuthContext);
87 | const {
88 | config
89 | } = useContext(FireactContext);
90 | const signInPath = config.pathnames.SignIn;
91 | if (authUser.checked) {
92 | if (authUser.user !== null) {
93 | return /*#__PURE__*/React.createElement(Outlet, null);
94 | } else {
95 | return /*#__PURE__*/React.createElement(Navigate, {
96 | to: signInPath + "?re=" + document.location.pathname + document.location.search + document.location.hash
97 | });
98 | }
99 | } else {
100 | return /*#__PURE__*/React.createElement(Box, {
101 | mt: 10
102 | }, /*#__PURE__*/React.createElement(Container, {
103 | maxWidth: "sm"
104 | }, /*#__PURE__*/React.createElement(Box, {
105 | component: "span",
106 | m: 5,
107 | textAlign: "center"
108 | }, loader)));
109 | }
110 | };
--------------------------------------------------------------------------------
/dist/esm/components/Fireact.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | export const FireactContext = /*#__PURE__*/React.createContext();
3 | export const FireactProvider = _ref => {
4 | let {
5 | config,
6 | children
7 | } = _ref;
8 | return /*#__PURE__*/React.createElement(FireactContext.Provider, {
9 | value: {
10 | config
11 | }
12 | }, children);
13 | };
--------------------------------------------------------------------------------
/dist/esm/components/SetPageTitle.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect } from "react";
2 | import { AuthContext } from "./Auth";
3 | export const SetPageTitle = _ref => {
4 | let {
5 | title
6 | } = _ref;
7 | const {
8 | brand
9 | } = useContext(AuthContext);
10 | useEffect(() => {
11 | document.title = brand ? "".concat(title, " - ").concat(brand) : title;
12 | }, [title, brand]);
13 | return /*#__PURE__*/React.createElement(React.Fragment, null);
14 | };
--------------------------------------------------------------------------------
/dist/esm/components/auth/ActionPages.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import "core-js/modules/web.url.js";
3 | import "core-js/modules/web.url-search-params.js";
4 | import "core-js/modules/es.regexp.exec.js";
5 | import "core-js/modules/es.regexp.test.js";
6 | import React, { useContext, useEffect, useState } from "react";
7 | import { Alert, Box, Stack, Typography, TextField, Button } from "@mui/material";
8 | import { SetPageTitle } from "../SetPageTitle";
9 | import { getAuth, applyActionCode, verifyPasswordResetCode, confirmPasswordReset } from "firebase/auth";
10 | import { NavLink } from "react-router-dom";
11 | import { FireactContext } from "../Fireact";
12 | export const ActionPages = _ref => {
13 | let {
14 | logo
15 | } = _ref;
16 | let title = "Unknown Action";
17 | const params = new URL(document.location).searchParams;
18 | const mode = params.get('mode');
19 | const actionCode = params.get('oobCode');
20 | // const apiKey = params.get('apiKey');
21 | // const continueUrl = params.get('continueUrl');
22 | // const lang = params.get('lang') || 'en';
23 |
24 | switch (mode) {
25 | case 'resetPassword':
26 | title = "Reset Password";
27 | break;
28 | case 'recoverEmail':
29 | title = 'Recover Email';
30 | break;
31 | case 'verifyEmail':
32 | title = 'Verfiy Email';
33 | break;
34 | default:
35 | break;
36 | }
37 | return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(SetPageTitle, {
38 | title: title
39 | }), logo, /*#__PURE__*/React.createElement(Typography, {
40 | component: "h1",
41 | variant: "h5"
42 | }, title)), /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Stack, {
43 | spacing: 2,
44 | mt: 2
45 | }, (mode === 'verifyEmail' || mode === 'recoverEmail') && /*#__PURE__*/React.createElement(HandleAction, {
46 | actionCode: actionCode,
47 | mode: mode
48 | }), mode === 'resetPassword' && /*#__PURE__*/React.createElement(ResetPassword, {
49 | actionCode: actionCode
50 | }))));
51 | };
52 | const ResetPassword = _ref2 => {
53 | let {
54 | actionCode
55 | } = _ref2;
56 | const [processing, setProcessing] = useState(false);
57 | const [error, setError] = useState(null);
58 | const [stage, setStage] = useState('verifying');
59 | const {
60 | config
61 | } = useContext(FireactContext);
62 | const [newPassword, setNewPassword] = useState('');
63 | const [confirmPassword, setConfirmPassword] = useState('');
64 | useEffect(() => {
65 | const auth = getAuth();
66 | verifyPasswordResetCode(auth, actionCode).then(() => {
67 | setStage('form');
68 | }).catch(error => {
69 | setStage('');
70 | setError(error.message);
71 | });
72 | }, [actionCode]);
73 | return /*#__PURE__*/React.createElement(React.Fragment, null, error && /*#__PURE__*/React.createElement(Alert, {
74 | severity: "error"
75 | }, error), stage === 'verifying' && /*#__PURE__*/React.createElement(Typography, null, "Please wait while verifying your request..."), stage === 'form' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TextField, {
76 | required: true,
77 | fullWidth: true,
78 | name: "newPassword",
79 | label: "New Password",
80 | type: "password",
81 | autoComplete: "new-password",
82 | margin: "normal",
83 | onChange: e => setNewPassword(e.target.value)
84 | }), /*#__PURE__*/React.createElement(TextField, {
85 | required: true,
86 | fullWidth: true,
87 | name: "confirmPassword",
88 | label: "Confirm Password",
89 | type: "password",
90 | autoComplete: "",
91 | margin: "normal",
92 | onChange: e => setConfirmPassword(e.target.value)
93 | }), /*#__PURE__*/React.createElement(Button, {
94 | type: "button",
95 | fullWidth: true,
96 | variant: "contained",
97 | size: "large",
98 | disabled: processing,
99 | onClick: () => {
100 | setProcessing(true);
101 | setError(null);
102 | const passwordNumericRegex = /\d+/;
103 | const passwordUppercaseRegex = /[A-Z]+/;
104 | const passwordLowercaseRegex = /[a-z]+/;
105 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
106 | if (!passwordNumericRegex.test(String(newPassword)) || !passwordUppercaseRegex.test(String(newPassword)) || !passwordLowercaseRegex.test(String(newPassword)) || !passwordSpecialRegex.test(String(newPassword)) || newPassword.length < 8) {
107 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
108 | setProcessing(false);
109 | } else if (newPassword !== confirmPassword) {
110 | setError('Confirm password does not match with new password.');
111 | setProcessing(false);
112 | } else {
113 | const auth = getAuth();
114 | confirmPasswordReset(auth, actionCode, newPassword).then(() => {
115 | setStage('success');
116 | }).catch(error => {
117 | setError(error.message);
118 | setProcessing(false);
119 | });
120 | }
121 | }
122 | }, "Reset Password")), stage === 'success' && /*#__PURE__*/React.createElement(Alert, {
123 | severity: "success"
124 | }, "Your email is verified. Please ", /*#__PURE__*/React.createElement(NavLink, {
125 | to: config.pathnames.SignIn
126 | }, "sign in"), " with your new password."));
127 | };
128 | const HandleAction = _ref3 => {
129 | let {
130 | mode,
131 | actionCode
132 | } = _ref3;
133 | const [processing, setProcessing] = useState(false);
134 | const [error, setError] = useState(null);
135 | const [success, setSuccess] = useState(false);
136 | const {
137 | config
138 | } = useContext(FireactContext);
139 | let processingMessage = 'Please wait';
140 | let successMessage = 'Done';
141 | switch (mode) {
142 | case 'verifyEmail':
143 | processingMessage = 'Please wait while verifying your email...';
144 | successMessage = /*#__PURE__*/React.createElement(React.Fragment, null, "Your email is verified. Please ", /*#__PURE__*/React.createElement(NavLink, {
145 | to: config.pathnames.SignIn
146 | }, "sign in"), " again.");
147 | break;
148 | case 'recoverEmail':
149 | processingMessage = 'Please wait while resotring your email...';
150 | successMessage = /*#__PURE__*/React.createElement(React.Fragment, null, "Your email is restored. Please ", /*#__PURE__*/React.createElement(NavLink, {
151 | to: config.pathnames.ResetPassword
152 | }, "reset password"), " to ensure your account is secured.");
153 | break;
154 | default:
155 | break;
156 | }
157 | useEffect(() => {
158 | setProcessing(true);
159 | setError(null);
160 | setSuccess(false);
161 | const auth = getAuth();
162 | applyActionCode(auth, actionCode).then(() => {
163 | setSuccess(true);
164 | setProcessing(false);
165 | }).catch(error => {
166 | setError(error.message);
167 | setProcessing(false);
168 | });
169 | }, [actionCode]);
170 | return /*#__PURE__*/React.createElement(React.Fragment, null, processing ? /*#__PURE__*/React.createElement(Typography, null, processingMessage) : success ? /*#__PURE__*/React.createElement(Alert, {
171 | severity: "success"
172 | }, successMessage) : error ? /*#__PURE__*/React.createElement(Alert, {
173 | severity: "error"
174 | }, error) : /*#__PURE__*/React.createElement(Alert, {
175 | severity: "error"
176 | }, "Something went wrong"));
177 | };
--------------------------------------------------------------------------------
/dist/esm/components/auth/ResetPassword.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import React, { useContext, useState } from "react";
3 | import { Alert, Button, Box, Stack, TextField, Typography, Grid, Link } from "@mui/material";
4 | import { Link as RouterLink } from "react-router-dom";
5 | import { getAuth, sendPasswordResetEmail } from "firebase/auth";
6 | import { SetPageTitle } from "../SetPageTitle";
7 | import { FireactContext } from "../Fireact";
8 | export const ResetPassword = _ref => {
9 | let {
10 | logo
11 | } = _ref;
12 | const {
13 | config
14 | } = useContext(FireactContext);
15 | const pathnames = config.pathnames;
16 | const signInUrl = pathnames.SignIn;
17 | const title = "Reset Password";
18 | const [error, setError] = useState(null);
19 | const [success, setSuccess] = useState(false);
20 | const [processing, setProcessing] = useState(false);
21 | const [email, setEmail] = useState("");
22 | return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(SetPageTitle, {
23 | title: title
24 | }), logo, /*#__PURE__*/React.createElement(Typography, {
25 | component: "h1",
26 | variant: "h5"
27 | }, title)), /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Stack, {
28 | spacing: 2,
29 | mt: 2
30 | }, error !== null && /*#__PURE__*/React.createElement(Alert, {
31 | severity: "error"
32 | }, error), success && /*#__PURE__*/React.createElement(Alert, {
33 | severity: "success"
34 | }, "A password reset email has been sent to the email address."), /*#__PURE__*/React.createElement(TextField, {
35 | required: true,
36 | fullWidth: true,
37 | name: "email",
38 | label: "Email",
39 | type: "email",
40 | autoComplete: "email",
41 | margin: "normal",
42 | onChange: e => setEmail(e.target.value)
43 | }), /*#__PURE__*/React.createElement(Button, {
44 | type: "button",
45 | fullWidth: true,
46 | variant: "contained",
47 | size: "large",
48 | disabled: processing,
49 | onClick: () => {
50 | setProcessing(true);
51 | setSuccess(false);
52 | setError(null);
53 | const auth = getAuth();
54 | sendPasswordResetEmail(auth, email).then(() => {
55 | setProcessing(false);
56 | setSuccess(true);
57 | }).catch(error => {
58 | switch (error.code) {
59 | case "auth/invalid-email":
60 | setError('The email address is badly formatted.');
61 | break;
62 | case "auth/missing-email":
63 | setError('The email address is missing.');
64 | break;
65 | case "auth/user-not-found":
66 | setError('There is no user record corresponding to this identifier. The user may have been deleted.');
67 | break;
68 | case "auth/too-many-requests":
69 | setError('We have blocked all requests from this device due to unusual activity. Try again later.');
70 | break;
71 | default:
72 | setError(error.message);
73 | break;
74 | }
75 | setProcessing(false);
76 | });
77 | }
78 | }, "Reset Password"), signInUrl && /*#__PURE__*/React.createElement(Grid, {
79 | container: true
80 | }, signInUrl && /*#__PURE__*/React.createElement(Grid, {
81 | item: true,
82 | xs: true,
83 | textAlign: "left"
84 | }, /*#__PURE__*/React.createElement(Link, {
85 | to: signInUrl,
86 | component: RouterLink
87 | }, "Sign in with an existing account"))))));
88 | };
--------------------------------------------------------------------------------
/dist/esm/components/auth/SignUp.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import "core-js/modules/es.string.trim.js";
3 | import "core-js/modules/es.regexp.exec.js";
4 | import "core-js/modules/es.regexp.test.js";
5 | import React, { useContext, useState } from "react";
6 | import { Alert, Button, Box, Stack, TextField, Typography, Grid, Link } from "@mui/material";
7 | import { getAuth, createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
8 | import { Link as RouterLink } from "react-router-dom";
9 | import { SetPageTitle } from "../SetPageTitle";
10 | import { FireactContext } from "../Fireact";
11 | export const SignUp = _ref => {
12 | let {
13 | logo,
14 | successUrl
15 | } = _ref;
16 | const {
17 | config
18 | } = useContext(FireactContext);
19 | const pathnames = config.pathnames;
20 | const title = "Sign Up";
21 | const signInUrl = pathnames.SignIn;
22 | const resetPasswordUrl = pathnames.ResetPassword;
23 | const re = successUrl || "/"; // redirect successUrl or homepage after sign in
24 |
25 | const [error, setError] = useState(null);
26 | const [processing, setProcessing] = useState(false);
27 | const [email, setEmail] = useState("");
28 | const [fullname, setFullname] = useState("");
29 | const [password, setPassword] = useState("");
30 | return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(SetPageTitle, {
31 | title: title
32 | }), logo, /*#__PURE__*/React.createElement(Typography, {
33 | component: "h1",
34 | variant: "h5"
35 | }, title)), /*#__PURE__*/React.createElement(Box, null, /*#__PURE__*/React.createElement(Stack, {
36 | spacing: 2,
37 | mt: 2
38 | }, error !== null && /*#__PURE__*/React.createElement(Alert, {
39 | severity: "error"
40 | }, error), /*#__PURE__*/React.createElement(TextField, {
41 | required: true,
42 | fullWidth: true,
43 | name: "email",
44 | label: "Email",
45 | type: "email",
46 | autoComplete: "email",
47 | margin: "normal",
48 | onChange: e => setEmail(e.target.value)
49 | }), /*#__PURE__*/React.createElement(TextField, {
50 | required: true,
51 | fullWidth: true,
52 | name: "fullname",
53 | label: "Full Name",
54 | autoComplete: "name",
55 | type: "text",
56 | margin: "normal",
57 | onChange: e => setFullname(e.target.value)
58 | }), /*#__PURE__*/React.createElement(TextField, {
59 | required: true,
60 | fullWidth: true,
61 | name: "password",
62 | label: "New Password",
63 | autoComplete: "new-password",
64 | type: "password",
65 | margin: "normal",
66 | onChange: e => setPassword(e.target.value)
67 | }), /*#__PURE__*/React.createElement(Button, {
68 | type: "button",
69 | fullWidth: true,
70 | variant: "contained",
71 | size: "large",
72 | disabled: processing,
73 | onClick: () => {
74 | setProcessing(true);
75 | setError(null);
76 | const passwordNumericRegex = /\d+/;
77 | const passwordUppercaseRegex = /[A-Z]+/;
78 | const passwordLowercaseRegex = /[a-z]+/;
79 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
80 | if (fullname.trim() === "") {
81 | setError('Your full name is required.');
82 | setProcessing(false);
83 | } else if (!passwordNumericRegex.test(String(password)) || !passwordUppercaseRegex.test(String(password)) || !passwordLowercaseRegex.test(String(password)) || !passwordSpecialRegex.test(String(password)) || password.length < 8) {
84 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
85 | setProcessing(false);
86 | } else {
87 | const auth = getAuth();
88 | createUserWithEmailAndPassword(auth, email, password).then(result => {
89 | return updateProfile(result.user, {
90 | displayName: fullname
91 | });
92 | }).then(() => {
93 | document.location.href = re.substr(0, 1) === '/' && re.substr(1, 1) !== '/' ? re : '/';
94 | }).catch(error => {
95 | switch (error.code) {
96 | case "auth/invalid-email":
97 | setError('The email address is badly formatted.');
98 | break;
99 | case "auth/missing-email":
100 | setError('The email address is missing.');
101 | break;
102 | case "auth/email-already-in-use":
103 | setError('The email address is already in use by another account.');
104 | break;
105 | default:
106 | setError(error.message);
107 | break;
108 | }
109 | setProcessing(false);
110 | });
111 | }
112 | }
113 | }, "Sign Up"), (signInUrl || resetPasswordUrl) && /*#__PURE__*/React.createElement(Grid, {
114 | container: true
115 | }, signInUrl && /*#__PURE__*/React.createElement(Grid, {
116 | item: true,
117 | xs: true,
118 | textAlign: "left"
119 | }, /*#__PURE__*/React.createElement(Link, {
120 | to: signInUrl,
121 | component: RouterLink
122 | }, "Sign in with an existing account")), resetPasswordUrl && /*#__PURE__*/React.createElement(Grid, {
123 | item: true,
124 | textAlign: "left"
125 | }, /*#__PURE__*/React.createElement(Link, {
126 | to: resetPasswordUrl,
127 | component: RouterLink
128 | }, "Reset password"))))));
129 | };
--------------------------------------------------------------------------------
/dist/esm/components/menus/MainMenu.js:
--------------------------------------------------------------------------------
1 | import { Divider, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material";
2 | import React, { useContext } from "react";
3 | import { NavLink } from "react-router-dom";
4 | import HomeIcon from '@mui/icons-material/Home';
5 | import AccountBoxIcon from '@mui/icons-material/AccountBox';
6 | import { FireactContext } from "../Fireact";
7 | export const MainMenu = _ref => {
8 | let {
9 | customItems
10 | } = _ref;
11 | const {
12 | config
13 | } = useContext(FireactContext);
14 | const pathnames = config.pathnames;
15 | const profileUrl = pathnames.UserProfile;
16 | return /*#__PURE__*/React.createElement(List, {
17 | component: "nav"
18 | }, /*#__PURE__*/React.createElement(NavLink, {
19 | to: "/",
20 | style: {
21 | textDecoration: 'none'
22 | },
23 | key: "home"
24 | }, /*#__PURE__*/React.createElement(ListItemButton, null, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(HomeIcon, null)), /*#__PURE__*/React.createElement(ListItemText, {
25 | primary: /*#__PURE__*/React.createElement(Typography, {
26 | color: "textPrimary"
27 | }, "Home")
28 | }))), customItems, profileUrl && [/*#__PURE__*/React.createElement(Divider, {
29 | key: "profile-divider"
30 | }), /*#__PURE__*/React.createElement(NavLink, {
31 | to: profileUrl,
32 | style: {
33 | textDecoration: 'none'
34 | },
35 | key: "profile"
36 | }, /*#__PURE__*/React.createElement(ListItemButton, null, /*#__PURE__*/React.createElement(ListItemIcon, null, /*#__PURE__*/React.createElement(AccountBoxIcon, null)), /*#__PURE__*/React.createElement(ListItemText, {
37 | primary: /*#__PURE__*/React.createElement(Typography, {
38 | color: "textPrimary"
39 | }, "My Profile")
40 | })))]);
41 | };
--------------------------------------------------------------------------------
/dist/esm/components/menus/UserMenu.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import { Avatar, Divider, IconButton, Menu, MenuItem } from "@mui/material";
3 | import React, { useContext, useState } from "react";
4 | import { AuthContext } from "../Auth";
5 | import AccountBoxIcon from '@mui/icons-material/AccountBox';
6 | import ExitToAppIcon from '@mui/icons-material/ExitToApp';
7 | import { getAuth, signOut } from "firebase/auth";
8 | import { useNavigate } from "react-router-dom";
9 | import { FireactContext } from "../Fireact";
10 | export const UserMenu = _ref => {
11 | let {
12 | customItems
13 | } = _ref;
14 | const {
15 | config
16 | } = useContext(FireactContext);
17 | const pathnames = config.pathnames;
18 | const profileUrl = pathnames.UserProfile;
19 | const [anchorEl, setAnchorEl] = useState(null);
20 | const open = Boolean(anchorEl);
21 | const handleMenu = event => {
22 | setAnchorEl(event.currentTarget);
23 | };
24 | const handleClose = () => {
25 | setAnchorEl(null);
26 | };
27 | const navigate = useNavigate();
28 | return /*#__PURE__*/React.createElement(AuthContext.Consumer, null, context => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(IconButton, {
29 | "ria-label": "account of current user",
30 | "aria-controls": "menu-appbar",
31 | onClick: handleMenu,
32 | "aria-haspopup": "true"
33 | }, /*#__PURE__*/React.createElement(Avatar, {
34 | alt: context.authUser.user.displayName,
35 | src: context.authUser.user.photoURL ? context.authUser.user.photoURL : "https://ui-avatars.com/api/?name=" + encodeURI(context.authUser.user.displayName) + "&background=007bff&size=64&color=f8f9fc"
36 | })), /*#__PURE__*/React.createElement(Menu, {
37 | id: "menu-appbar",
38 | anchorEl: anchorEl,
39 | anchorOrigin: {
40 | vertical: 'bottom',
41 | horizontal: 'right'
42 | },
43 | keepMounted: true,
44 | transformOrigin: {
45 | vertical: 'top',
46 | horizontal: 'right'
47 | },
48 | open: open,
49 | onClose: handleClose
50 | }, profileUrl && [/*#__PURE__*/React.createElement(MenuItem, {
51 | key: "profile-menu-item",
52 | onClick: e => {
53 | e.preventDefault();
54 | handleClose();
55 | navigate(profileUrl);
56 | }
57 | }, /*#__PURE__*/React.createElement(AccountBoxIcon, {
58 | sx: {
59 | marginRight: "10px"
60 | }
61 | }), " Profile"), /*#__PURE__*/React.createElement(Divider, {
62 | key: "profile-menu-divider"
63 | })], customItems, /*#__PURE__*/React.createElement(MenuItem, {
64 | onClick: e => {
65 | e.preventDefault();
66 | handleClose();
67 | const auth = getAuth();
68 | signOut(auth).then(() => {
69 | document.location.href = "/";
70 | });
71 | }
72 | }, /*#__PURE__*/React.createElement(ExitToAppIcon, {
73 | sx: {
74 | marginRight: "10px"
75 | }
76 | }), " Sign Out"))));
77 | };
--------------------------------------------------------------------------------
/dist/esm/components/templates/AppTemplate.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import "core-js/modules/es.symbol.description.js";
3 | function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4 | function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5 | function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6 | function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
7 | function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
8 | import React, { useContext, useState } from "react";
9 | import { styled, useTheme } from '@mui/material/styles';
10 | import { AppBar as MuiAppBar, Box, CssBaseline, Drawer as MuiDrawer, IconButton, Toolbar, Divider, Typography, Button } from "@mui/material";
11 | import MenuIcon from '@mui/icons-material/Menu';
12 | import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
13 | import ChevronRightIcon from '@mui/icons-material/ChevronRight';
14 | import { Outlet, useNavigate } from "react-router-dom";
15 | import { FireactContext } from "../Fireact";
16 | const drawerWidth = 240;
17 | const openedMixin = theme => ({
18 | width: drawerWidth,
19 | transition: theme.transitions.create('width', {
20 | easing: theme.transitions.easing.sharp,
21 | duration: theme.transitions.duration.enteringScreen
22 | }),
23 | overflowX: 'hidden'
24 | });
25 | const closedMixin = theme => ({
26 | transition: theme.transitions.create('width', {
27 | easing: theme.transitions.easing.sharp,
28 | duration: theme.transitions.duration.leavingScreen
29 | }),
30 | overflowX: 'hidden',
31 | width: "calc(".concat(theme.spacing(7), " + 1px)"),
32 | [theme.breakpoints.up('sm')]: {
33 | width: "calc(".concat(theme.spacing(9), " + 1px)")
34 | }
35 | });
36 | const DrawerHeader = styled('div')(_ref => {
37 | let {
38 | theme
39 | } = _ref;
40 | return _objectSpread({
41 | display: 'flex',
42 | alignItems: 'center',
43 | justifyContent: 'flex-end',
44 | padding: theme.spacing(0, 1)
45 | }, theme.mixins.toolbar);
46 | });
47 | const AppBar = styled(MuiAppBar, {
48 | shouldForwardProp: prop => prop !== 'open'
49 | })(_ref2 => {
50 | let {
51 | theme,
52 | open
53 | } = _ref2;
54 | return _objectSpread({
55 | zIndex: theme.zIndex.drawer + 1,
56 | transition: theme.transitions.create(['width', 'margin'], {
57 | easing: theme.transitions.easing.sharp,
58 | duration: theme.transitions.duration.leavingScreen
59 | })
60 | }, open && {
61 | marginLeft: drawerWidth,
62 | width: "calc(100% - ".concat(drawerWidth, "px)"),
63 | transition: theme.transitions.create(['width', 'margin'], {
64 | easing: theme.transitions.easing.sharp,
65 | duration: theme.transitions.duration.enteringScreen
66 | })
67 | });
68 | });
69 | const Drawer = styled(MuiDrawer, {
70 | shouldForwardProp: prop => prop !== 'open'
71 | })(_ref3 => {
72 | let {
73 | theme,
74 | open
75 | } = _ref3;
76 | return _objectSpread(_objectSpread({
77 | width: drawerWidth,
78 | flexShrink: 0,
79 | whiteSpace: 'nowrap',
80 | boxSizing: 'border-box'
81 | }, open && _objectSpread(_objectSpread({}, openedMixin(theme)), {}, {
82 | '& .MuiDrawer-paper': openedMixin(theme)
83 | })), !open && _objectSpread(_objectSpread({}, closedMixin(theme)), {}, {
84 | '& .MuiDrawer-paper': closedMixin(theme)
85 | }));
86 | });
87 | export const AppTemplate = _ref4 => {
88 | let {
89 | logo,
90 | drawerMenu,
91 | toolbarChildren,
92 | toolBarMenu
93 | } = _ref4;
94 | const theme = useTheme();
95 | const [open, setOpen] = useState(true);
96 | const handleDrawerOpen = () => {
97 | setOpen(true);
98 | };
99 | const handleDrawerClose = () => {
100 | setOpen(false);
101 | };
102 | const {
103 | config
104 | } = useContext(FireactContext);
105 | const brand = config.brand;
106 | const navigate = useNavigate();
107 | return /*#__PURE__*/React.createElement(Box, {
108 | sx: {
109 | display: "flex"
110 | }
111 | }, /*#__PURE__*/React.createElement(CssBaseline, null), /*#__PURE__*/React.createElement(AppBar, {
112 | position: "fixed",
113 | open: open
114 | }, /*#__PURE__*/React.createElement(Toolbar, null, /*#__PURE__*/React.createElement(IconButton, {
115 | color: "inherit",
116 | "aria-label": "open drawer",
117 | onClick: handleDrawerOpen,
118 | edge: "start",
119 | sx: _objectSpread({
120 | marginRight: '36px'
121 | }, open && {
122 | display: 'none'
123 | })
124 | }, /*#__PURE__*/React.createElement(MenuIcon, null)), toolbarChildren, /*#__PURE__*/React.createElement("div", {
125 | style: {
126 | marginLeft: "auto",
127 | marginRight: "0px"
128 | }
129 | }, toolBarMenu))), /*#__PURE__*/React.createElement(Drawer, {
130 | variant: "permanent",
131 | open: open
132 | }, /*#__PURE__*/React.createElement(DrawerHeader, null, open && /*#__PURE__*/React.createElement("div", {
133 | style: {
134 | marginLeft: '0px',
135 | marginRight: 'auto',
136 | display: 'inline-flex',
137 | alignItems: 'center',
138 | flexWrap: 'wrap'
139 | }
140 | }, /*#__PURE__*/React.createElement(Button, {
141 | style: {
142 | color: "#000000"
143 | },
144 | onClick: () => navigate("/")
145 | }, /*#__PURE__*/React.createElement("div", {
146 | style: {
147 | display: 'inline-flex',
148 | paddingRight: '20px'
149 | }
150 | }, logo), /*#__PURE__*/React.createElement(Typography, {
151 | variant: "h6"
152 | }, brand))), /*#__PURE__*/React.createElement(IconButton, {
153 | onClick: handleDrawerClose
154 | }, theme.direction === 'rtl' ? /*#__PURE__*/React.createElement(ChevronRightIcon, null) : /*#__PURE__*/React.createElement(ChevronLeftIcon, null))), /*#__PURE__*/React.createElement(Divider, null), drawerMenu, /*#__PURE__*/React.createElement(Divider, null)), /*#__PURE__*/React.createElement(Box, {
155 | component: "main",
156 | sx: {
157 | flexGrow: 1,
158 | backgroundColor: theme => theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900],
159 | height: '100vh',
160 | overflow: 'auto'
161 | }
162 | }, /*#__PURE__*/React.createElement(DrawerHeader, null), /*#__PURE__*/React.createElement("div", {
163 | style: {
164 | position: 'relative'
165 | }
166 | }, /*#__PURE__*/React.createElement(Box, {
167 | mt: 5,
168 | ml: 3,
169 | mr: 3,
170 | mb: 3
171 | }, /*#__PURE__*/React.createElement(Outlet, null)))));
172 | };
--------------------------------------------------------------------------------
/dist/esm/components/templates/PublicTemplate.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Container } from "@mui/material";
3 | import { Outlet } from "react-router-dom";
4 | export const PublicTemplate = () => {
5 | return /*#__PURE__*/React.createElement(Box, {
6 | mt: 10
7 | }, /*#__PURE__*/React.createElement(Container, {
8 | maxWidth: "sm"
9 | }, /*#__PURE__*/React.createElement(Box, {
10 | component: "span",
11 | m: 5,
12 | textAlign: "center"
13 | }, /*#__PURE__*/React.createElement(Outlet, null))));
14 | };
--------------------------------------------------------------------------------
/dist/esm/components/user/UserDelete.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
3 | import React, { useContext, useState } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import { SetPageTitle } from "../SetPageTitle";
6 | import { deleteUser, getAuth } from "firebase/auth";
7 | import { FireactContext } from "../Fireact";
8 | export const UserDelete = () => {
9 | const [email, setEmail] = useState("");
10 | const [error, setError] = useState(null);
11 | const [processing, setProcessing] = useState(false);
12 | const title = "Delete Account";
13 | const navigate = useNavigate();
14 | const auth = getAuth();
15 | const {
16 | config
17 | } = useContext(FireactContext);
18 | const pathnames = config.pathnames;
19 | return /*#__PURE__*/React.createElement(Container, {
20 | maxWidth: "md"
21 | }, /*#__PURE__*/React.createElement(SetPageTitle, {
22 | title: title
23 | }), /*#__PURE__*/React.createElement(Paper, null, /*#__PURE__*/React.createElement(Box, {
24 | p: 2
25 | }, /*#__PURE__*/React.createElement(Typography, {
26 | component: "h1",
27 | variant: "h4",
28 | align: "center"
29 | }, title)), error !== null && /*#__PURE__*/React.createElement(Box, {
30 | p: 2
31 | }, /*#__PURE__*/React.createElement(Alert, {
32 | severity: "error"
33 | }, error)), /*#__PURE__*/React.createElement(Box, {
34 | p: 2
35 | }, /*#__PURE__*/React.createElement(Typography, null, "Please confirm your email address to delete your user account."), /*#__PURE__*/React.createElement(TextField, {
36 | required: true,
37 | fullWidth: true,
38 | name: "email",
39 | label: "Email Address",
40 | type: "email",
41 | autoComplete: "email",
42 | margin: "normal",
43 | onChange: e => setEmail(e.target.value)
44 | })), /*#__PURE__*/React.createElement(Box, {
45 | p: 2
46 | }, /*#__PURE__*/React.createElement(Grid, {
47 | container: true
48 | }, /*#__PURE__*/React.createElement(Grid, {
49 | item: true,
50 | xs: true
51 | }, /*#__PURE__*/React.createElement(Button, {
52 | type: "button",
53 | color: "secondary",
54 | variant: "outlined",
55 | disabled: processing,
56 | onClick: () => {
57 | navigate(pathnames.UserProfile);
58 | }
59 | }, "Back")), /*#__PURE__*/React.createElement(Grid, {
60 | item: true
61 | }, /*#__PURE__*/React.createElement(Button, {
62 | type: "button",
63 | color: "error",
64 | variant: "contained",
65 | disabled: processing,
66 | onClick: () => {
67 | setProcessing(true);
68 | setError(null);
69 | if (auth.currentUser.email !== email) {
70 | setError("The email address does not match with your email address.");
71 | setProcessing(false);
72 | } else {
73 | deleteUser(auth.currentUser).then(() => {
74 | // refresh page
75 | document.location.href = "/";
76 | }).catch(error => {
77 | switch (error.code) {
78 | case "auth/requires-recent-login":
79 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
80 | break;
81 | default:
82 | setError(error.message);
83 | break;
84 | }
85 | setProcessing(false);
86 | });
87 | }
88 | }
89 | }, "Delete User Account"))))));
90 | };
--------------------------------------------------------------------------------
/dist/esm/components/user/UserProfile.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import { Alert, Grid, List, ListItem, Box, Avatar, Typography, Divider, Paper, Container } from "@mui/material";
3 | import React, { useContext, useState } from "react";
4 | import { AuthContext } from "../Auth";
5 | import EditIcon from '@mui/icons-material/Edit';
6 | import SendIcon from '@mui/icons-material/Send';
7 | import VerifiedUserIcon from '@mui/icons-material/VerifiedUser';
8 | import { useNavigate } from "react-router-dom";
9 | import { SetPageTitle } from "../SetPageTitle";
10 | import { getAuth, sendEmailVerification } from "firebase/auth";
11 | import { FireactContext } from "../Fireact";
12 | export const UserProfile = () => {
13 | const navigate = useNavigate();
14 | const auth = getAuth();
15 | const [sendVerification, setSendVerification] = useState({
16 | 'success': false,
17 | 'error': null
18 | });
19 | const {
20 | config
21 | } = useContext(FireactContext);
22 | const pathnames = config.pathnames;
23 | return /*#__PURE__*/React.createElement(AuthContext.Consumer, null, context => /*#__PURE__*/React.createElement(Container, {
24 | maxWidth: "md"
25 | }, /*#__PURE__*/React.createElement(SetPageTitle, {
26 | title: "User Profile"
27 | }), /*#__PURE__*/React.createElement(Paper, null, sendVerification.error !== null && /*#__PURE__*/React.createElement(Box, {
28 | p: 2
29 | }, /*#__PURE__*/React.createElement(Alert, {
30 | severity: "error"
31 | }, sendVerification.error)), sendVerification.success && /*#__PURE__*/React.createElement(Box, {
32 | p: 2
33 | }, /*#__PURE__*/React.createElement(Alert, {
34 | severity: "success"
35 | }, "Please check your email inbox to verify the email address. Refresh this page after you verified your email address.")), /*#__PURE__*/React.createElement(List, {
36 | component: "nav"
37 | }, /*#__PURE__*/React.createElement(ListItem, null, /*#__PURE__*/React.createElement(Grid, {
38 | container: true,
39 | spacing: 1
40 | }, /*#__PURE__*/React.createElement(Grid, {
41 | item: true,
42 | xs: true
43 | }, /*#__PURE__*/React.createElement(Box, {
44 | p: 1
45 | }, /*#__PURE__*/React.createElement("strong", null, "AVATAR"), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Typography, {
46 | color: "textSecondary"
47 | }, "Update via social login")), /*#__PURE__*/React.createElement(Box, {
48 | p: 1
49 | })), /*#__PURE__*/React.createElement(Grid, {
50 | item: true,
51 | sx: {
52 | flexDirection: "column",
53 | display: "flex",
54 | justifyContent: "center"
55 | }
56 | }, /*#__PURE__*/React.createElement(Avatar, {
57 | alt: context.authUser.user.displayName,
58 | src: context.authUser.user.photoURL ? context.authUser.user.photoURL : "https://ui-avatars.com/api/?name=" + encodeURI(context.authUser.user.displayName) + "&background=007bff&size=64&color=f8f9fc",
59 | style: {
60 | height: '64px',
61 | width: '64px'
62 | }
63 | })))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(ListItem, {
64 | button: true,
65 | onClick: () => {
66 | navigate(pathnames.UserUpdateName);
67 | }
68 | }, /*#__PURE__*/React.createElement(Grid, {
69 | container: true,
70 | spacing: 1
71 | }, /*#__PURE__*/React.createElement(Grid, {
72 | item: true,
73 | xs: true
74 | }, /*#__PURE__*/React.createElement(Box, {
75 | p: 1
76 | }, /*#__PURE__*/React.createElement("strong", null, "NAME"), /*#__PURE__*/React.createElement("br", null), context.authUser.user.displayName)), /*#__PURE__*/React.createElement(Grid, {
77 | item: true,
78 | sx: {
79 | flexDirection: "column",
80 | display: "flex",
81 | justifyContent: "center"
82 | }
83 | }, /*#__PURE__*/React.createElement(EditIcon, null)))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(ListItem, {
84 | button: true,
85 | onClick: () => {
86 | navigate(pathnames.UserUpdateEmail);
87 | }
88 | }, /*#__PURE__*/React.createElement(Grid, {
89 | container: true,
90 | spacing: 1
91 | }, /*#__PURE__*/React.createElement(Grid, {
92 | item: true,
93 | xs: true
94 | }, /*#__PURE__*/React.createElement(Box, {
95 | p: 1
96 | }, /*#__PURE__*/React.createElement("strong", null, "EMAIL"), /*#__PURE__*/React.createElement("br", null), context.authUser.user.email)), /*#__PURE__*/React.createElement(Grid, {
97 | item: true,
98 | sx: {
99 | flexDirection: "column",
100 | display: "flex",
101 | justifyContent: "center"
102 | }
103 | }, /*#__PURE__*/React.createElement(EditIcon, null)))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(ListItem, {
104 | button: true,
105 | onClick: () => {
106 | if (!context.authUser.user.emailVerified) {
107 | setSendVerification({
108 | 'success': false,
109 | 'error': null
110 | });
111 | sendEmailVerification(auth.currentUser).then(() => {
112 | setSendVerification({
113 | 'success': true,
114 | 'error': null
115 | });
116 | }).catch(error => {
117 | switch (error.code) {
118 | case "auth/too-many-requests":
119 | setSendVerification({
120 | 'success': false,
121 | 'error': "We have blocked all requests from this device due to unusual activity. Try again later."
122 | });
123 | break;
124 | default:
125 | setSendVerification({
126 | 'success': false,
127 | 'error': error.message
128 | });
129 | break;
130 | }
131 | });
132 | }
133 | }
134 | }, /*#__PURE__*/React.createElement(Grid, {
135 | container: true,
136 | spacing: 1
137 | }, /*#__PURE__*/React.createElement(Grid, {
138 | item: true,
139 | xs: true
140 | }, /*#__PURE__*/React.createElement(Box, {
141 | p: 1
142 | }, /*#__PURE__*/React.createElement("strong", null, "EMAIL VERIFIED"), /*#__PURE__*/React.createElement("br", null), context.authUser.user.emailVerified ? " Verified" : "Unverified email")), /*#__PURE__*/React.createElement(Grid, {
143 | item: true,
144 | sx: {
145 | flexDirection: "column",
146 | display: "flex",
147 | justifyContent: "center"
148 | }
149 | }, context.authUser.user.emailVerified ? /*#__PURE__*/React.createElement(VerifiedUserIcon, null) : /*#__PURE__*/React.createElement(SendIcon, null)))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(ListItem, {
150 | button: true,
151 | onClick: () => {
152 | navigate(pathnames.UserUpdatePassword);
153 | }
154 | }, /*#__PURE__*/React.createElement(Grid, {
155 | container: true,
156 | spacing: 1
157 | }, /*#__PURE__*/React.createElement(Grid, {
158 | item: true,
159 | xs: true
160 | }, /*#__PURE__*/React.createElement(Box, {
161 | p: 1
162 | }, /*#__PURE__*/React.createElement("strong", null, "PASSWORD"), /*#__PURE__*/React.createElement("br", null), "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022")), /*#__PURE__*/React.createElement(Grid, {
163 | item: true,
164 | sx: {
165 | flexDirection: "column",
166 | display: "flex",
167 | justifyContent: "center"
168 | }
169 | }, /*#__PURE__*/React.createElement(EditIcon, null)))), /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(ListItem, {
170 | button: true,
171 | onClick: () => {
172 | navigate(pathnames.UserDelete);
173 | }
174 | }, /*#__PURE__*/React.createElement(Grid, {
175 | container: true,
176 | spacing: 1
177 | }, /*#__PURE__*/React.createElement(Grid, {
178 | container: true,
179 | item: true,
180 | xs: 12,
181 | md: 4
182 | }, /*#__PURE__*/React.createElement(Box, {
183 | p: 1
184 | }, /*#__PURE__*/React.createElement(Typography, {
185 | color: "error"
186 | }, /*#__PURE__*/React.createElement("strong", null, "DELETE ACCOUNT"))))))))));
187 | };
--------------------------------------------------------------------------------
/dist/esm/components/user/UserUpdateEmail.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
3 | import React, { useContext, useState } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import { SetPageTitle } from "../SetPageTitle";
6 | import { getAuth, updateEmail } from "firebase/auth";
7 | import { FireactContext } from "../Fireact";
8 | export const UserUpdateEmail = () => {
9 | const [email, setEmail] = useState("");
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 | const [processing, setProcessing] = useState(false);
13 | const title = "Change Email";
14 | const navigate = useNavigate();
15 | const auth = getAuth();
16 | const {
17 | config
18 | } = useContext(FireactContext);
19 | const pathnames = config.pathnames;
20 | return /*#__PURE__*/React.createElement(Container, {
21 | maxWidth: "md"
22 | }, /*#__PURE__*/React.createElement(SetPageTitle, {
23 | title: title
24 | }), /*#__PURE__*/React.createElement(Paper, null, /*#__PURE__*/React.createElement(Box, {
25 | p: 2
26 | }, /*#__PURE__*/React.createElement(Typography, {
27 | component: "h1",
28 | variant: "h4",
29 | align: "center"
30 | }, title)), error !== null && /*#__PURE__*/React.createElement(Box, {
31 | p: 2
32 | }, /*#__PURE__*/React.createElement(Alert, {
33 | severity: "error"
34 | }, error)), success && /*#__PURE__*/React.createElement(Box, {
35 | p: 2
36 | }, /*#__PURE__*/React.createElement(Alert, {
37 | severity: "success"
38 | }, "Your email address has been updated successfully.")), /*#__PURE__*/React.createElement(Box, {
39 | p: 2
40 | }, /*#__PURE__*/React.createElement(TextField, {
41 | required: true,
42 | fullWidth: true,
43 | name: "email",
44 | label: "New Email Address",
45 | type: "email",
46 | autoComplete: "email",
47 | margin: "normal",
48 | onChange: e => setEmail(e.target.value)
49 | })), /*#__PURE__*/React.createElement(Box, {
50 | p: 2
51 | }, /*#__PURE__*/React.createElement(Grid, {
52 | container: true
53 | }, /*#__PURE__*/React.createElement(Grid, {
54 | item: true,
55 | xs: true
56 | }, /*#__PURE__*/React.createElement(Button, {
57 | type: "button",
58 | color: "secondary",
59 | variant: "outlined",
60 | disabled: processing,
61 | onClick: () => {
62 | navigate(pathnames.UserProfile);
63 | }
64 | }, "Back")), /*#__PURE__*/React.createElement(Grid, {
65 | item: true
66 | }, /*#__PURE__*/React.createElement(Button, {
67 | type: "button",
68 | variant: "contained",
69 | disabled: processing,
70 | onClick: () => {
71 | setProcessing(true);
72 | setSuccess(false);
73 | setError(null);
74 | updateEmail(auth.currentUser, email).then(() => {
75 | setSuccess(true);
76 | setProcessing(false);
77 | }).catch(error => {
78 | switch (error.code) {
79 | case "auth/requires-recent-login":
80 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
81 | break;
82 | case "auth/email-already-in-use":
83 | setError("The email address is already in use by another account.");
84 | break;
85 | default:
86 | setError(error.message);
87 | break;
88 | }
89 | setProcessing(false);
90 | });
91 | }
92 | }, "Save"))))));
93 | };
--------------------------------------------------------------------------------
/dist/esm/components/user/UserUpdateName.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import "core-js/modules/es.string.trim.js";
3 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
4 | import React, { useContext, useState } from "react";
5 | import { useNavigate } from "react-router-dom";
6 | import { SetPageTitle } from "../SetPageTitle";
7 | import { getAuth, updateProfile } from "firebase/auth";
8 | import { FireactContext } from "../Fireact";
9 | export const UserUpdateName = () => {
10 | const [fullname, setFullname] = useState("");
11 | const [error, setError] = useState(null);
12 | const [success, setSuccess] = useState(false);
13 | const [processing, setProcessing] = useState(false);
14 | const title = "Change Name";
15 | const navigate = useNavigate();
16 | const auth = getAuth();
17 | const {
18 | config
19 | } = useContext(FireactContext);
20 | const pathnames = config.pathnames;
21 | return /*#__PURE__*/React.createElement(Container, {
22 | maxWidth: "md"
23 | }, /*#__PURE__*/React.createElement(SetPageTitle, {
24 | title: title
25 | }), /*#__PURE__*/React.createElement(Paper, null, /*#__PURE__*/React.createElement(Box, {
26 | p: 2
27 | }, /*#__PURE__*/React.createElement(Typography, {
28 | component: "h1",
29 | variant: "h4",
30 | align: "center"
31 | }, title)), error !== null && /*#__PURE__*/React.createElement(Box, {
32 | p: 2
33 | }, /*#__PURE__*/React.createElement(Alert, {
34 | severity: "error"
35 | }, error)), success && /*#__PURE__*/React.createElement(Box, {
36 | p: 2
37 | }, /*#__PURE__*/React.createElement(Alert, {
38 | severity: "success"
39 | }, "Your name has been updated successfully.")), /*#__PURE__*/React.createElement(Box, {
40 | p: 2
41 | }, /*#__PURE__*/React.createElement(TextField, {
42 | required: true,
43 | fullWidth: true,
44 | name: "fullname",
45 | label: "Full Name",
46 | autoComplete: "name",
47 | type: "text",
48 | margin: "normal",
49 | onChange: e => setFullname(e.target.value)
50 | })), /*#__PURE__*/React.createElement(Box, {
51 | p: 2
52 | }, /*#__PURE__*/React.createElement(Grid, {
53 | container: true
54 | }, /*#__PURE__*/React.createElement(Grid, {
55 | item: true,
56 | xs: true
57 | }, /*#__PURE__*/React.createElement(Button, {
58 | type: "button",
59 | color: "secondary",
60 | variant: "outlined",
61 | disabled: processing,
62 | onClick: () => {
63 | navigate(pathnames.UserProfile);
64 | }
65 | }, "Back")), /*#__PURE__*/React.createElement(Grid, {
66 | item: true
67 | }, /*#__PURE__*/React.createElement(Button, {
68 | type: "button",
69 | variant: "contained",
70 | disabled: processing,
71 | onClick: () => {
72 | setProcessing(true);
73 | setSuccess(false);
74 | setError(null);
75 | if (fullname.trim() === "") {
76 | setError('Your full name is required.');
77 | setProcessing(false);
78 | } else {
79 | updateProfile(auth.currentUser, {
80 | displayName: fullname
81 | }).then(() => {
82 | setSuccess(true);
83 | setProcessing(false);
84 | }).catch(error => {
85 | switch (error.code) {
86 | case "auth/requires-recent-login":
87 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
88 | break;
89 | default:
90 | setError(error.message);
91 | break;
92 | }
93 | setProcessing(false);
94 | });
95 | }
96 | }
97 | }, "Save"))))));
98 | };
--------------------------------------------------------------------------------
/dist/esm/components/user/UserUpdatePassword.js:
--------------------------------------------------------------------------------
1 | import "core-js/modules/web.dom-collections.iterator.js";
2 | import "core-js/modules/es.regexp.exec.js";
3 | import "core-js/modules/es.regexp.test.js";
4 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
5 | import React, { useContext, useState } from "react";
6 | import { useNavigate } from "react-router-dom";
7 | import { SetPageTitle } from "../SetPageTitle";
8 | import { getAuth, updatePassword } from "firebase/auth";
9 | import { FireactContext } from "../Fireact";
10 | export const UserUpdatePassword = () => {
11 | const [password, setPassword] = useState("");
12 | const [error, setError] = useState(null);
13 | const [success, setSuccess] = useState(false);
14 | const [processing, setProcessing] = useState(false);
15 | const title = "Change Password";
16 | const navigate = useNavigate();
17 | const auth = getAuth();
18 | const {
19 | config
20 | } = useContext(FireactContext);
21 | const pathnames = config.pathnames;
22 | return /*#__PURE__*/React.createElement(Container, {
23 | maxWidth: "md"
24 | }, /*#__PURE__*/React.createElement(SetPageTitle, {
25 | title: title
26 | }), /*#__PURE__*/React.createElement(Paper, null, /*#__PURE__*/React.createElement(Box, {
27 | p: 2
28 | }, /*#__PURE__*/React.createElement(Typography, {
29 | component: "h1",
30 | variant: "h4",
31 | align: "center"
32 | }, title)), error !== null && /*#__PURE__*/React.createElement(Box, {
33 | p: 2
34 | }, /*#__PURE__*/React.createElement(Alert, {
35 | severity: "error"
36 | }, error)), success && /*#__PURE__*/React.createElement(Box, {
37 | p: 2
38 | }, /*#__PURE__*/React.createElement(Alert, {
39 | severity: "success"
40 | }, "Your password has been updated successfully.")), /*#__PURE__*/React.createElement(Box, {
41 | p: 2
42 | }, /*#__PURE__*/React.createElement(TextField, {
43 | required: true,
44 | fullWidth: true,
45 | name: "password",
46 | label: "New Password",
47 | autoComplete: "new-password",
48 | type: "password",
49 | margin: "normal",
50 | onChange: e => setPassword(e.target.value)
51 | })), /*#__PURE__*/React.createElement(Box, {
52 | p: 2
53 | }, /*#__PURE__*/React.createElement(Grid, {
54 | container: true
55 | }, /*#__PURE__*/React.createElement(Grid, {
56 | item: true,
57 | xs: true
58 | }, /*#__PURE__*/React.createElement(Button, {
59 | type: "button",
60 | color: "secondary",
61 | variant: "outlined",
62 | disabled: processing,
63 | onClick: () => {
64 | navigate(pathnames.UserProfile);
65 | }
66 | }, "Back")), /*#__PURE__*/React.createElement(Grid, {
67 | item: true
68 | }, /*#__PURE__*/React.createElement(Button, {
69 | type: "button",
70 | variant: "contained",
71 | disabled: processing,
72 | onClick: () => {
73 | const passwordNumericRegex = /\d+/;
74 | const passwordUppercaseRegex = /[A-Z]+/;
75 | const passwordLowercaseRegex = /[a-z]+/;
76 | const passwordSpecialRegex = /[ !"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]+/;
77 | setProcessing(true);
78 | setSuccess(false);
79 | setError(null);
80 | if (!passwordNumericRegex.test(String(password)) || !passwordUppercaseRegex.test(String(password)) || !passwordLowercaseRegex.test(String(password)) || !passwordSpecialRegex.test(String(password)) || password.length < 8) {
81 | setError('The password must contain at least 8 characters with letters (both uppercase and lowercase), numbers, and symbols.');
82 | setProcessing(false);
83 | } else {
84 | updatePassword(auth.currentUser, password).then(() => {
85 | setSuccess(true);
86 | setProcessing(false);
87 | }).catch(error => {
88 | switch (error.code) {
89 | case "auth/requires-recent-login":
90 | setError("This operation is sensitive and requires recent authentication. Log in again before retrying this request.");
91 | break;
92 | default:
93 | setError(error.message);
94 | break;
95 | }
96 | setProcessing(false);
97 | });
98 | }
99 | }
100 | }, "Save"))))));
101 | };
--------------------------------------------------------------------------------
/dist/esm/index.js:
--------------------------------------------------------------------------------
1 | import { AuthContext, AuthProvider, AuthRoutes } from "./components/Auth";
2 | import { UserDelete } from "./components/user/UserDelete";
3 | import { PublicTemplate } from "./components/templates/PublicTemplate";
4 | import { SignIn } from "./components/auth/SignIn";
5 | import { SignUp } from "./components/auth/SignUp";
6 | import { ResetPassword } from "./components/auth/ResetPassword";
7 | import { AppTemplate } from "./components/templates/AppTemplate";
8 | import { UserMenu } from "./components/menus/UserMenu";
9 | import { MainMenu } from "./components/menus/MainMenu";
10 | import { UserProfile } from "./components/user/UserProfile";
11 | import { UserUpdateEmail } from "./components/user/UserUpdateEmail";
12 | import { UserUpdateName } from "./components/user/UserUpdateName";
13 | import { UserUpdatePassword } from "./components/user/UserUpdatePassword";
14 | import { SetPageTitle } from "./components/SetPageTitle";
15 | import { FireactContext, FireactProvider } from "./components/Fireact";
16 | import { ActionPages } from './components/auth/ActionPages';
17 | import pathnames from "./pathnames.json";
18 | export { pathnames, ActionPages, AppTemplate, AuthContext, AuthProvider, AuthRoutes, FireactContext, FireactProvider, MainMenu, PublicTemplate, ResetPassword, SetPageTitle, SignIn, SignUp, UserDelete, UserMenu, UserProfile, UserUpdateEmail, UserUpdateName, UserUpdatePassword };
--------------------------------------------------------------------------------
/dist/esm/pathnames.json:
--------------------------------------------------------------------------------
1 | {
2 | "ActionPages": "/auth-action",
3 | "ResetPassword": "/reset-password",
4 | "SignIn": "/sign-in",
5 | "SignUp": "/sign-up",
6 | "UserDelete": "/user/delete",
7 | "UserProfile": "/user",
8 | "UserUpdateEmail": "/user/update-email",
9 | "UserUpdateName": "/user/update-name",
10 | "UserUpdatePassword": "/user/update-password"
11 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@fireactjs/core",
3 | "version": "1.1.2",
4 | "private": false,
5 | "author": "Chaoming Li",
6 | "keywords": [
7 | "react",
8 | "components",
9 | "ui",
10 | "firebase",
11 | "authentication",
12 | "auth"
13 | ],
14 | "main": "dist/cjs/index.js",
15 | "module": "dist/esm/index.js",
16 | "files": [
17 | "dist",
18 | "README.md",
19 | "LICENSE"
20 | ],
21 | "license": "ISC",
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/fireactjs/core.git"
25 | },
26 | "dependencies": {
27 | "@babel/polyfill": "^7.12.1"
28 | },
29 | "peerDependencies": {
30 | "@emotion/react": "^11.11.3",
31 | "@emotion/styled": "^11.11.0",
32 | "@mui/icons-material": "^5.15.3",
33 | "@mui/material": "^5.15.3",
34 | "firebase": "^10.7.1",
35 | "react": "^18.2.0",
36 | "react-dom": "^18.2.0",
37 | "react-router-dom": "^6.21.1",
38 | "react-scripts": "5.0.1",
39 | "web-vitals": "^2.1.4"
40 | },
41 | "scripts": {
42 | "start": "PUBLIC_URL=/ react-scripts start",
43 | "build": "rm -rf dist && NODE_ENV=production babel src/lib --out-dir dist/esm --copy-files --config-file ./babel.config.esm.json && NODE_ENV=production babel src/lib --out-dir dist/cjs --copy-files --config-file ./babel.config.cjs.json",
44 | "test": "react-scripts test",
45 | "eject": "react-scripts eject"
46 | },
47 | "eslintConfig": {
48 | "extends": [
49 | "react-app",
50 | "react-app/jest"
51 | ]
52 | },
53 | "browserslist": {
54 | "production": [
55 | ">0.2%",
56 | "not dead",
57 | "not op_mini all"
58 | ],
59 | "development": [
60 | "last 1 chrome version",
61 | "last 1 firefox version",
62 | "last 1 safari version"
63 | ]
64 | },
65 | "devDependencies": {
66 | "@babel/cli": "^7.23.4",
67 | "@babel/core": "^7.23.7",
68 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
69 | "@babel/preset-env": "^7.23.7",
70 | "@testing-library/jest-dom": "^5.17.0",
71 | "@testing-library/react": "^13.4.0",
72 | "@testing-library/user-event": "^13.5.0",
73 | "core-js": "^3.35.0",
74 | "webpack": "^5.89.0",
75 | "webpack-cli": "^5.1.4"
76 | },
77 | "description": "fireactjs-core is the core package for building web applications with Firebase and Reactjs in a simple and fast approach. Its key features include:",
78 | "bugs": {
79 | "url": "https://github.com/fireactjs/core/issues"
80 | },
81 | "homepage": "https://github.com/fireactjs/core#readme"
82 | }
83 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireactjs/core/b1dc41bd474f75a425f786ec51837b2fdb901ed8/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireactjs/core/b1dc41bd474f75a425f786ec51837b2fdb901ed8/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fireactjs/core/b1dc41bd474f75a425f786ec51837b2fdb901ed8/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Fireact",
3 | "name": "Fireact Web Application",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import firebaseConfig from "./firebaseConfig.json";
3 | import { pathnames, ActionPages, AppTemplate, AuthProvider, AuthRoutes, FireactProvider, MainMenu, PublicTemplate, ResetPassword, SignIn, SignUp, UserMenu, UserProfile, UserUpdateEmail, UserUpdateName, UserUpdatePassword, UserDelete } from './lib';
4 | import { BrowserRouter, Routes } from "react-router-dom";
5 | import { Route } from "react-router-dom";
6 | import LocalFireDepartmentIcon from '@mui/icons-material/LocalFireDepartment';
7 | import { CircularProgress, Box } from '@mui/material';
8 | import authMethods from "./authMethods.json";
9 |
10 | const Logo = ({size, color}) => {
11 | const logoColor = color || 'warning';
12 | return (
13 |
14 | );
15 | }
16 |
17 | const Loader = ({size}) => {
18 | let cpSize = "35px";
19 | switch(size){
20 | case "small":
21 | cpSize = "30px";
22 | break;
23 | case "medium":
24 | cpSize = "35px";
25 | break;
26 | case "large":
27 | cpSize = "45px";
28 | break;
29 | default:
30 | cpSize = "35px";
31 | break;
32 | }
33 | return (
34 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 | }
42 |
43 | function App() {
44 |
45 | const config = {
46 | firebaseConfig: firebaseConfig,
47 | brand: "FIREACTJS",
48 | pathnames: pathnames,
49 | authProviders: authMethods
50 | }
51 |
52 | return (
53 |
54 |
55 |
56 |
57 | } />} >
58 | } toolBarMenu={} drawerMenu={} />}>
59 | >} />
60 | } />
61 | } />
62 | } />
63 | } />
64 | } />
65 |
66 |
67 | }>
68 | }
71 | />
72 | } />
73 | }
76 | />
77 | } />
78 | }
81 | />
82 | } />
83 | }
86 | />
87 | } />
88 |
89 |
90 |
91 |
92 |
93 | )
94 | }
95 |
96 | export default App;
97 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/src/authMethods.json:
--------------------------------------------------------------------------------
1 | {
2 | "google": true,
3 | "facebook": true,
4 | "microsoft": true,
5 | "apple": true,
6 | "twitter": true,
7 | "github": true
8 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/src/lib/assets/images/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/src/lib/assets/images/microsoft.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/lib/components/Auth.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState, useContext } from "react";
2 | import { initializeApp } from 'firebase/app';
3 | import { getAuth, onAuthStateChanged } from 'firebase/auth';
4 | import { Navigate, Outlet } from "react-router-dom";
5 | import { Box, Container } from "@mui/material";
6 | import { doc, getFirestore, setDoc } from "firebase/firestore";
7 | import { FireactContext } from "./Fireact";
8 | import { getFunctions } from "firebase/functions";
9 |
10 | export const AuthContext = React.createContext();
11 |
12 | export const AuthProvider = ({children}) => {
13 |
14 | // authorized user state
15 | const [authUser, setAuthUser] = useState(
16 | {
17 | user: null,
18 | data: {},
19 | checked: false
20 | }
21 | );
22 |
23 | const { config } = useContext(FireactContext);
24 | const [firebaseApp, setFirebaseApp] = useState(null);
25 | const [authInstance, setAuthInstance] = useState(null);
26 | const [firestoreInstance, setFirestoreInstance] = useState(null);
27 | const [functionsInstance, setFunctionsInstance] = useState(null);
28 |
29 | useEffect(() => {
30 | const app = initializeApp(config.firebaseConfig);
31 | const auth = getAuth(app);
32 | const firestore = getFirestore(app);
33 | const functions = getFunctions(app);
34 |
35 | setFirebaseApp(app);
36 | setAuthInstance(auth);
37 | setFirestoreInstance(firestore);
38 | setFunctionsInstance(functions);
39 |
40 | onAuthStateChanged(auth, (user) => {
41 | if(user !== null){
42 | user.getIdToken().then(token => {
43 | const userDoc = doc(firestore, 'users', user.uid);
44 | setAuthUser(prevState => ({
45 | ...prevState,
46 | user: user,
47 | checked: true
48 | }));
49 | setDoc(userDoc, {
50 | displayName: user.displayName,
51 | photoURL: user.photoURL,
52 | email: user.email
53 | },{merge: true});
54 | });
55 | }else{
56 | setAuthUser(prevState => ({
57 | ...prevState,
58 | user: null,
59 | checked: true
60 | }));
61 | }
62 | });
63 | },[config.firebaseConfig]);
64 |
65 | return (
66 |
69 | {children}
70 |
71 | )
72 | }
73 |
74 | export const AuthRoutes = ({ loader }) => {
75 | const { authUser } = useContext(AuthContext);
76 | const { config } = useContext(FireactContext);
77 | const signInPath = config.pathnames.SignIn;
78 |
79 | if(authUser.checked){
80 | if(authUser.user !== null){
81 | return
82 | }else{
83 | return
84 | }
85 | }else{
86 | return (
87 |
88 |
89 |
90 | {loader}
91 |
92 |
93 |
94 | )
95 | }
96 | }
--------------------------------------------------------------------------------
/src/lib/components/Fireact.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | export const FireactContext = React.createContext();
4 |
5 | export const FireactProvider = ({config, children}) => {
6 | return (
7 |
8 | {children}
9 |
10 | )
11 | }
--------------------------------------------------------------------------------
/src/lib/components/SetPageTitle.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect } from "react"
2 | import { AuthContext } from "./Auth"
3 |
4 | export const SetPageTitle = ({title}) => {
5 | const { brand } = useContext(AuthContext);
6 | useEffect(() => {
7 | document.title = brand?(`${title} - ${brand}`):(title);
8 | }, [title, brand]);
9 | return (<>>);
10 | }
--------------------------------------------------------------------------------
/src/lib/components/auth/ActionPages.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useState } from "react";
2 | import {Alert, Box, Stack, Typography, TextField, Button } from "@mui/material";
3 | import { SetPageTitle } from "../SetPageTitle";
4 | import { getAuth, applyActionCode, verifyPasswordResetCode, confirmPasswordReset } from "firebase/auth";
5 | import { NavLink } from "react-router-dom";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const ActionPages = ({logo}) => {
9 | let title = "Unknown Action";
10 | const params = (new URL(document.location)).searchParams;
11 |
12 | const mode = params.get('mode');
13 | const actionCode = params.get('oobCode');
14 | // const apiKey = params.get('apiKey');
15 | // const continueUrl = params.get('continueUrl');
16 | // const lang = params.get('lang') || 'en';
17 |
18 | switch(mode){
19 | case 'resetPassword':
20 | title = "Reset Password";
21 | break;
22 | case 'recoverEmail':
23 | title = 'Recover Email';
24 | break;
25 | case 'verifyEmail':
26 | title = 'Verfiy Email';
27 | break;
28 | default:
29 | break;
30 | }
31 |
32 | return (
33 | <>
34 |
35 |
36 | {logo}
37 | {title}
38 |
39 |
40 |
41 | {(mode === 'verifyEmail' || mode === 'recoverEmail') && }
42 | {mode === 'resetPassword' &&
43 |
44 | }
45 |
46 |
47 | >
48 | )
49 | }
50 |
51 | const ResetPassword = ({actionCode}) => {
52 | const [processing, setProcessing] = useState(false);
53 | const [error, setError] = useState(null);
54 | const [stage, setStage] = useState('verifying');
55 |
56 | const { config } = useContext(FireactContext);
57 |
58 | const [newPassword, setNewPassword] = useState('');
59 | const [confirmPassword, setConfirmPassword] = useState('');
60 |
61 | useEffect(() => {
62 | const auth = getAuth();
63 | verifyPasswordResetCode(auth, actionCode).then(() => {
64 | setStage('form');
65 | }).catch(error => {
66 | setStage('');
67 | setError(error.message);
68 | })
69 | },[actionCode]);
70 |
71 | return (
72 | <>
73 | {error && {error}}
74 | {stage === 'verifying' &&
75 | Please wait while verifying your request...
76 | }
77 | {stage === 'form' && <>
78 | setNewPassword(e.target.value)} />
79 | setConfirmPassword(e.target.value)} />
80 |
106 | >}
107 | {stage === 'success' &&
108 | Your email is verified. Please sign in with your new password.
109 | }
110 | >
111 | )
112 |
113 | }
114 |
115 | const HandleAction = ({mode, actionCode}) => {
116 | const [processing, setProcessing] = useState(false);
117 | const [error, setError] = useState(null);
118 | const [success, setSuccess] = useState(false);
119 |
120 | const { config } = useContext(FireactContext);
121 |
122 | let processingMessage = 'Please wait';
123 | let successMessage = 'Done';
124 |
125 | switch(mode){
126 | case 'verifyEmail':
127 | processingMessage = 'Please wait while verifying your email...';
128 | successMessage = <>Your email is verified. Please sign in again.>
129 | break;
130 | case 'recoverEmail':
131 | processingMessage = 'Please wait while resotring your email...';
132 | successMessage = <>Your email is restored. Please reset password to ensure your account is secured.>
133 | break;
134 | default:
135 | break;
136 | }
137 |
138 | useEffect(() => {
139 | setProcessing(true);
140 | setError(null);
141 | setSuccess(false);
142 | const auth = getAuth();
143 | applyActionCode(auth, actionCode).then(() => {
144 | setSuccess(true);
145 | setProcessing(false);
146 | }).catch(error => {
147 | setError(error.message);
148 | setProcessing(false);
149 | })
150 |
151 | },[actionCode]);
152 |
153 | return (
154 | <>
155 | {processing?(
156 | {processingMessage}
157 | ):(
158 | success?(
159 | {successMessage}
160 | ):(
161 | error?(
162 | {error}
163 | ):(
164 | Something went wrong
165 | )
166 | )
167 | )}
168 | >
169 | )
170 | }
--------------------------------------------------------------------------------
/src/lib/components/auth/ResetPassword.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import { Alert, Button, Box, Stack, TextField, Typography, Grid, Link } from "@mui/material";
3 | import { Link as RouterLink } from "react-router-dom";
4 | import { getAuth, sendPasswordResetEmail } from "firebase/auth";
5 | import { SetPageTitle } from "../SetPageTitle";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const ResetPassword = ({logo}) => {
9 | const { config } = useContext(FireactContext);
10 | const pathnames = config.pathnames;
11 |
12 | const signInUrl = pathnames.SignIn;
13 | const title = "Reset Password";
14 |
15 | const [error, setError] = useState(null);
16 | const [success, setSuccess] = useState(false);
17 | const [processing, setProcessing] = useState(false);
18 | const [email, setEmail] = useState("");
19 |
20 | return (
21 | <>
22 |
23 |
24 | {logo}
25 | {title}
26 |
27 |
28 |
29 | {error !== null &&
30 | {error}
31 | }
32 | {success &&
33 | A password reset email has been sent to the email address.
34 | }
35 | setEmail(e.target.value)} />
36 |
65 | {(signInUrl &&
66 |
67 | {signInUrl &&
68 |
69 | Sign in with an existing account
70 |
71 | }
72 |
73 | )}
74 |
75 |
76 | >
77 | );
78 | }
--------------------------------------------------------------------------------
/src/lib/components/auth/SignUp.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import { Alert, Button, Box, Stack, TextField, Typography, Grid, Link } from "@mui/material";
3 | import { getAuth, createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
4 | import { Link as RouterLink } from "react-router-dom";
5 | import { SetPageTitle } from "../SetPageTitle";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const SignUp = ({logo, successUrl}) => {
9 | const { config } = useContext(FireactContext);
10 | const pathnames = config.pathnames;
11 |
12 | const title = "Sign Up";
13 | const signInUrl = pathnames.SignIn;
14 | const resetPasswordUrl = pathnames.ResetPassword;
15 |
16 | const re = successUrl || "/"; // redirect successUrl or homepage after sign in
17 |
18 | const [error, setError] = useState(null);
19 | const [processing, setProcessing] = useState(false);
20 | const [email, setEmail] = useState("");
21 | const [fullname, setFullname] = useState("");
22 | const [password, setPassword] = useState("");
23 |
24 | return (
25 | <>
26 |
27 |
28 | {logo}
29 | {title}
30 |
31 |
32 |
33 | {error !== null &&
34 | {error}
35 | }
36 | setEmail(e.target.value)} />
37 | setFullname(e.target.value)} />
38 | setPassword(e.target.value)} />
39 |
80 | {(signInUrl || resetPasswordUrl) &&
81 |
82 | {signInUrl &&
83 |
84 | Sign in with an existing account
85 |
86 | }
87 | {resetPasswordUrl &&
88 |
89 | Reset password
90 |
91 | }
92 |
93 | }
94 |
95 |
96 | >
97 | );
98 | }
--------------------------------------------------------------------------------
/src/lib/components/menus/MainMenu.js:
--------------------------------------------------------------------------------
1 | import { Divider, List, ListItemButton, ListItemIcon, ListItemText, Typography } from "@mui/material";
2 | import React, { useContext } from "react";
3 | import { NavLink } from "react-router-dom";
4 | import HomeIcon from '@mui/icons-material/Home';
5 | import AccountBoxIcon from '@mui/icons-material/AccountBox';
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const MainMenu = ({customItems}) => {
9 | const { config } = useContext(FireactContext);
10 | const pathnames = config.pathnames;
11 | const profileUrl = pathnames.UserProfile;
12 | return (
13 |
14 |
15 |
16 |
17 | Home} />
18 |
19 |
20 | {customItems}
21 | {profileUrl && [
22 | ,
23 |
24 |
25 |
26 | My Profile} />
27 |
28 |
29 | ]}
30 |
31 | )
32 | }
--------------------------------------------------------------------------------
/src/lib/components/menus/UserMenu.js:
--------------------------------------------------------------------------------
1 | import { Avatar, Divider, IconButton, Menu, MenuItem } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { AuthContext } from "../Auth";
4 | import AccountBoxIcon from '@mui/icons-material/AccountBox';
5 | import ExitToAppIcon from '@mui/icons-material/ExitToApp';
6 | import { getAuth, signOut } from "firebase/auth";
7 | import { useNavigate } from "react-router-dom";
8 | import { FireactContext } from "../Fireact";
9 |
10 |
11 | export const UserMenu = ({customItems}) => {
12 |
13 | const { config } = useContext(FireactContext);
14 | const pathnames = config.pathnames;
15 |
16 | const profileUrl = pathnames.UserProfile;
17 | const [anchorEl, setAnchorEl] = useState(null);
18 | const open = Boolean(anchorEl);
19 | const handleMenu = (event) => {
20 | setAnchorEl(event.currentTarget);
21 | };
22 | const handleClose = () => {
23 | setAnchorEl(null);
24 | };
25 |
26 | const navigate = useNavigate();
27 |
28 | return (
29 |
30 | {(context) => (
31 | <>
32 |
33 |
34 |
35 |
74 | >
75 | )}
76 |
77 | )
78 | }
--------------------------------------------------------------------------------
/src/lib/components/templates/AppTemplate.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from "react";
2 | import { styled, useTheme } from '@mui/material/styles';
3 | import { AppBar as MuiAppBar, Box, CssBaseline, Drawer as MuiDrawer, IconButton, Toolbar, Divider, Typography, Button } from "@mui/material";
4 | import MenuIcon from '@mui/icons-material/Menu';
5 | import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
6 | import ChevronRightIcon from '@mui/icons-material/ChevronRight';
7 | import { Outlet, useNavigate } from "react-router-dom";
8 | import { FireactContext } from "../Fireact";
9 |
10 | const drawerWidth = 240;
11 |
12 | const openedMixin = (theme) => ({
13 | width: drawerWidth,
14 | transition: theme.transitions.create('width', {
15 | easing: theme.transitions.easing.sharp,
16 | duration: theme.transitions.duration.enteringScreen,
17 | }),
18 | overflowX: 'hidden',
19 | });
20 |
21 | const closedMixin = (theme) => ({
22 | transition: theme.transitions.create('width', {
23 | easing: theme.transitions.easing.sharp,
24 | duration: theme.transitions.duration.leavingScreen,
25 | }),
26 | overflowX: 'hidden',
27 | width: `calc(${theme.spacing(7)} + 1px)`,
28 | [theme.breakpoints.up('sm')]: {
29 | width: `calc(${theme.spacing(9)} + 1px)`,
30 | },
31 | });
32 |
33 | const DrawerHeader = styled('div')(({ theme }) => ({
34 | display: 'flex',
35 | alignItems: 'center',
36 | justifyContent: 'flex-end',
37 | padding: theme.spacing(0, 1),
38 | // necessary for content to be below app bar
39 | ...theme.mixins.toolbar,
40 | }));
41 |
42 | const AppBar = styled(MuiAppBar, {
43 | shouldForwardProp: (prop) => prop !== 'open',
44 | })(({ theme, open }) => ({
45 | zIndex: theme.zIndex.drawer + 1,
46 | transition: theme.transitions.create(['width', 'margin'], {
47 | easing: theme.transitions.easing.sharp,
48 | duration: theme.transitions.duration.leavingScreen,
49 | }),
50 | ...(open && {
51 | marginLeft: drawerWidth,
52 | width: `calc(100% - ${drawerWidth}px)`,
53 | transition: theme.transitions.create(['width', 'margin'], {
54 | easing: theme.transitions.easing.sharp,
55 | duration: theme.transitions.duration.enteringScreen,
56 | }),
57 | }),
58 | }));
59 |
60 | const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
61 | ({ theme, open }) => ({
62 | width: drawerWidth,
63 | flexShrink: 0,
64 | whiteSpace: 'nowrap',
65 | boxSizing: 'border-box',
66 | ...(open && {
67 | ...openedMixin(theme),
68 | '& .MuiDrawer-paper': openedMixin(theme),
69 | }),
70 | ...(!open && {
71 | ...closedMixin(theme),
72 | '& .MuiDrawer-paper': closedMixin(theme),
73 | }),
74 | }),
75 | );
76 |
77 | export const AppTemplate = ({logo, drawerMenu, toolbarChildren, toolBarMenu}) => {
78 | const theme = useTheme();
79 | const [open, setOpen] = useState(true);
80 |
81 | const handleDrawerOpen = () => {
82 | setOpen(true);
83 | };
84 |
85 | const handleDrawerClose = () => {
86 | setOpen(false);
87 | };
88 |
89 | const {config} = useContext(FireactContext);
90 | const brand = config.brand;
91 | const navigate = useNavigate();
92 |
93 | return (
94 |
95 |
96 |
97 |
98 |
107 |
108 |
109 | {toolbarChildren}
110 | {toolBarMenu}
114 |
115 |
116 |
117 |
118 | {open &&
119 |
125 |
}
126 |
127 | {theme.direction === 'rtl' ? : }
128 |
129 |
130 |
131 | {drawerMenu}
132 |
133 |
134 |
137 | theme.palette.mode === 'light'
138 | ? theme.palette.grey[100]
139 | : theme.palette.grey[900],
140 | height: '100vh',
141 | overflow: 'auto'
142 | }}>
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | )
152 | }
--------------------------------------------------------------------------------
/src/lib/components/templates/PublicTemplate.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Box, Container } from "@mui/material";
3 | import { Outlet } from "react-router-dom";
4 |
5 | export const PublicTemplate = () => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | )
15 | }
--------------------------------------------------------------------------------
/src/lib/components/user/UserDelete.js:
--------------------------------------------------------------------------------
1 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import { SetPageTitle } from "../SetPageTitle";
5 | import { deleteUser, getAuth } from "firebase/auth";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const UserDelete = () => {
9 | const [email, setEmail] = useState("");
10 | const [error, setError] = useState(null);
11 | const [processing, setProcessing] = useState(false);
12 | const title = "Delete Account";
13 | const navigate = useNavigate();
14 |
15 | const auth = getAuth();
16 |
17 | const { config } = useContext(FireactContext);
18 | const pathnames = config.pathnames;
19 |
20 | return (
21 |
22 |
23 |
24 |
25 | {title}
26 |
27 | {error !== null &&
28 |
29 | {error}
30 |
31 | }
32 |
33 | Please confirm your email address to delete your user account.
34 | setEmail(e.target.value)} />
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
67 |
68 |
69 |
70 |
71 |
72 | )
73 | }
--------------------------------------------------------------------------------
/src/lib/components/user/UserProfile.js:
--------------------------------------------------------------------------------
1 | import { Alert, Grid, List, ListItem, Box, Avatar, Typography, Divider, Paper, Container } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { AuthContext } from "../Auth";
4 | import EditIcon from '@mui/icons-material/Edit';
5 | import SendIcon from '@mui/icons-material/Send';
6 | import VerifiedUserIcon from '@mui/icons-material/VerifiedUser';
7 | import { useNavigate } from "react-router-dom";
8 | import { SetPageTitle } from "../SetPageTitle";
9 | import { getAuth, sendEmailVerification } from "firebase/auth";
10 | import { FireactContext } from "../Fireact";
11 |
12 | export const UserProfile = () => {
13 | const navigate = useNavigate();
14 | const auth = getAuth();
15 | const [sendVerification, setSendVerification] = useState({
16 | 'success': false,
17 | 'error': null
18 | })
19 |
20 | const { config } = useContext(FireactContext);
21 | const pathnames = config.pathnames;
22 |
23 | return (
24 |
25 | {context => (
26 |
27 |
28 |
29 | {sendVerification.error !== null &&
30 |
31 | {sendVerification.error}
32 |
33 | }
34 | {sendVerification.success &&
35 |
36 | Please check your email inbox to verify the email address. Refresh this page after you verified your email address.
37 |
38 | }
39 |
40 |
41 |
42 |
43 | AVATAR
Update via social login
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | {
53 | navigate(pathnames.UserUpdateName);
54 | }}>
55 |
56 |
57 | NAME
{context.authUser.user.displayName}
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | {
66 | navigate(pathnames.UserUpdateEmail);
67 | }}>
68 |
69 |
70 | EMAIL
{context.authUser.user.email}
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {
79 | if(!context.authUser.user.emailVerified){
80 | setSendVerification({
81 | 'success': false,
82 | 'error': null
83 | });
84 | sendEmailVerification(auth.currentUser).then(() => {
85 | setSendVerification({
86 | 'success': true,
87 | 'error': null
88 | });
89 | }).catch(error => {
90 | switch(error.code){
91 | case "auth/too-many-requests":
92 | setSendVerification({
93 | 'success': false,
94 | 'error': "We have blocked all requests from this device due to unusual activity. Try again later."
95 | });
96 | break;
97 | default:
98 | setSendVerification({
99 | 'success': false,
100 | 'error': error.message
101 | });
102 | break;
103 | }
104 | });
105 | }
106 | }}>
107 |
108 |
109 | EMAIL VERIFIED
{(context.authUser.user.emailVerified?" Verified":"Unverified email")}
110 |
111 |
112 | {context.authUser.user.emailVerified?():()}
113 |
114 |
115 |
116 |
117 | {
118 | navigate(pathnames.UserUpdatePassword);
119 | }}>
120 |
121 |
122 | PASSWORD
••••••••
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | {
131 | navigate(pathnames.UserDelete);
132 | }}>
133 |
134 |
135 | DELETE ACCOUNT
136 |
137 |
138 |
139 |
140 |
141 |
142 | )}
143 |
144 | )
145 | }
--------------------------------------------------------------------------------
/src/lib/components/user/UserUpdateEmail.js:
--------------------------------------------------------------------------------
1 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import { SetPageTitle } from "../SetPageTitle";
5 | import { getAuth, updateEmail } from "firebase/auth";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const UserUpdateEmail = () => {
9 | const [email, setEmail] = useState("");
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 | const [processing, setProcessing] = useState(false);
13 | const title = "Change Email";
14 | const navigate = useNavigate();
15 |
16 | const auth = getAuth();
17 |
18 | const { config } = useContext(FireactContext)
19 | const pathnames = config.pathnames;
20 |
21 | return (
22 |
23 |
24 |
25 |
26 | {title}
27 |
28 | {error !== null &&
29 |
30 | {error}
31 |
32 | }
33 | {success &&
34 |
35 | Your email address has been updated successfully.
36 |
37 | }
38 |
39 | setEmail(e.target.value)} />
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
71 |
72 |
73 |
74 |
75 |
76 | )
77 | }
--------------------------------------------------------------------------------
/src/lib/components/user/UserUpdateName.js:
--------------------------------------------------------------------------------
1 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import { SetPageTitle } from "../SetPageTitle";
5 | import { getAuth, updateProfile } from "firebase/auth";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const UserUpdateName = () => {
9 | const [fullname, setFullname] = useState("");
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 | const [processing, setProcessing] = useState(false);
13 | const title = "Change Name";
14 | const navigate = useNavigate();
15 |
16 | const auth = getAuth();
17 |
18 | const { config } = useContext(FireactContext);
19 | const pathnames = config.pathnames;
20 |
21 | return (
22 |
23 |
24 |
25 |
26 | {title}
27 |
28 | {error !== null &&
29 |
30 | {error}
31 |
32 | }
33 | {success &&
34 |
35 | Your name has been updated successfully.
36 |
37 | }
38 |
39 | setFullname(e.target.value)} />
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
73 |
74 |
75 |
76 |
77 |
78 | )
79 | }
--------------------------------------------------------------------------------
/src/lib/components/user/UserUpdatePassword.js:
--------------------------------------------------------------------------------
1 | import { Alert, Box, Button, Container, Grid, Paper, TextField, Typography } from "@mui/material";
2 | import React, { useContext, useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 | import { SetPageTitle } from "../SetPageTitle";
5 | import { getAuth, updatePassword } from "firebase/auth";
6 | import { FireactContext } from "../Fireact";
7 |
8 | export const UserUpdatePassword = () => {
9 | const [password, setPassword] = useState("");
10 | const [error, setError] = useState(null);
11 | const [success, setSuccess] = useState(false);
12 | const [processing, setProcessing] = useState(false);
13 | const title = "Change Password";
14 | const navigate = useNavigate();
15 |
16 | const auth = getAuth();
17 |
18 | const { config } = useContext(FireactContext);
19 | const pathnames = config.pathnames;
20 |
21 | return (
22 |
23 |
24 |
25 |
26 | {title}
27 |
28 | {error !== null &&
29 |
30 | {error}
31 |
32 | }
33 | {success &&
34 |
35 | Your password has been updated successfully.
36 |
37 | }
38 |
39 | setPassword(e.target.value)} />
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
80 |
81 |
82 |
83 |
84 |
85 | )
86 | }
--------------------------------------------------------------------------------
/src/lib/index.js:
--------------------------------------------------------------------------------
1 | import { AuthContext, AuthProvider, AuthRoutes } from "./components/Auth";
2 | import { UserDelete } from "./components/user/UserDelete";
3 | import { PublicTemplate } from "./components/templates/PublicTemplate";
4 | import { SignIn } from "./components/auth/SignIn";
5 | import { SignUp } from "./components/auth/SignUp";
6 | import { ResetPassword } from "./components/auth/ResetPassword";
7 | import { AppTemplate } from "./components/templates/AppTemplate";
8 | import { UserMenu } from "./components/menus/UserMenu";
9 | import { MainMenu } from "./components/menus/MainMenu";
10 | import { UserProfile } from "./components/user/UserProfile";
11 | import { UserUpdateEmail } from "./components/user/UserUpdateEmail";
12 | import { UserUpdateName } from "./components/user/UserUpdateName";
13 | import { UserUpdatePassword } from "./components/user/UserUpdatePassword";
14 | import { SetPageTitle } from "./components/SetPageTitle";
15 | import { FireactContext, FireactProvider } from "./components/Fireact";
16 | import { ActionPages } from './components/auth/ActionPages';
17 |
18 | import pathnames from "./pathnames.json";
19 |
20 | export {
21 | pathnames,
22 | ActionPages,
23 | AppTemplate,
24 | AuthContext,
25 | AuthProvider,
26 | AuthRoutes,
27 | FireactContext,
28 | FireactProvider,
29 | MainMenu,
30 | PublicTemplate,
31 | ResetPassword,
32 | SetPageTitle,
33 | SignIn,
34 | SignUp,
35 | UserDelete,
36 | UserMenu,
37 | UserProfile,
38 | UserUpdateEmail,
39 | UserUpdateName,
40 | UserUpdatePassword
41 | }
--------------------------------------------------------------------------------
/src/lib/pathnames.json:
--------------------------------------------------------------------------------
1 | {
2 | "ActionPages": "/auth-action",
3 | "ResetPassword": "/reset-password",
4 | "SignIn": "/sign-in",
5 | "SignUp": "/sign-up",
6 | "UserDelete": "/user/delete",
7 | "UserProfile": "/user",
8 | "UserUpdateEmail": "/user/update-email",
9 | "UserUpdateName": "/user/update-name",
10 | "UserUpdatePassword": "/user/update-password"
11 | }
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------