├── .eslintrc.json ├── .gitbook └── assets │ ├── screenshot-2021-09-22-211556.png │ ├── spaces_gitbook_avatar-rectangle (1).png │ └── spaces_gitbook_avatar-rectangle.png ├── .github └── workflows │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SUMMARY.md ├── base-tsconfig.json ├── concept.md ├── documentation └── getting_started.md ├── getting-started.md ├── lerna.json ├── package-lock.json ├── package.json └── packages ├── README.md ├── base-shell ├── .gitignore ├── README.md ├── create-base-shell │ ├── index.js │ ├── package.json │ └── template │ │ ├── .gitignore │ │ ├── README.md │ │ ├── index.html │ │ ├── jsconfig.json │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ │ ├── src │ │ ├── config │ │ │ ├── config.jsx │ │ │ ├── defaultRoutes.jsx │ │ │ ├── index.js │ │ │ ├── locales │ │ │ │ ├── de.js │ │ │ │ ├── en.js │ │ │ │ ├── index.js │ │ │ │ └── ru.js │ │ │ ├── menuItems.js │ │ │ └── routes.jsx │ │ ├── containers │ │ │ └── Menu │ │ │ │ └── index.jsx │ │ ├── demo-index.jsx │ │ └── pages │ │ │ ├── About │ │ │ └── index.jsx │ │ │ ├── Home │ │ │ └── index.jsx │ │ │ ├── LandingPage │ │ │ └── index.jsx │ │ │ ├── PageNotFound │ │ │ └── index.jsx │ │ │ └── SignIn │ │ │ └── index.jsx │ │ └── vite.config.js ├── cypress.config.ts ├── cypress │ ├── e2e │ │ └── spec.cy.js │ ├── fixtures │ │ └── example.json │ └── support │ │ ├── commands.js │ │ └── e2e.js ├── index.html ├── package.json ├── src │ ├── components │ │ ├── AuthorizedRoute │ │ │ └── index.tsx │ │ ├── UnauthorizedRoute │ │ │ └── index.tsx │ │ └── index.ts │ ├── containers │ │ ├── App │ │ │ └── index.tsx │ │ ├── Layout │ │ │ └── index.tsx │ │ └── index.ts │ ├── index.ts │ ├── providers │ │ ├── AddToHomeScreen │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Auth │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Config │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Locale │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Online │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── SimpleValues │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Update │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ └── index.ts │ └── utils │ │ ├── config.ts │ │ ├── index.ts │ │ └── locale.ts ├── tsconfig.json └── vite.config.ts ├── bootstrap-shell ├── .gitignore ├── .travis.yml ├── .vscode │ └── launch.json ├── README.md ├── cra-template-bs │ ├── README.md │ ├── package.json │ ├── template.json │ └── template │ │ ├── gitignore │ │ ├── jsconfig.json │ │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ │ └── src │ │ ├── App.js │ │ ├── components │ │ ├── Loading.js │ │ ├── Loading │ │ │ └── Loading.js │ │ └── Menu │ │ │ └── MenuRight.js │ │ ├── config │ │ ├── config.js │ │ ├── dark.scss │ │ ├── index.js │ │ ├── locales │ │ │ ├── de.js │ │ │ ├── en.js │ │ │ ├── index.js │ │ │ └── ru.js │ │ ├── menuItems.js │ │ ├── routes.js │ │ └── themes.js │ │ ├── index.js │ │ └── pages │ │ ├── DialogDemo │ │ └── index.js │ │ ├── Home │ │ └── Home.js │ │ ├── LandingPage │ │ ├── LandingPage.js │ │ └── index.js │ │ └── PageNotFound │ │ └── PageNotFound.js ├── demo │ └── src │ │ └── index.js ├── nwb.config.js ├── package-lock.json ├── package.json ├── src │ ├── assets │ │ └── rmw.svg │ ├── components │ │ ├── Menu │ │ │ ├── Menu.js │ │ │ ├── MenuDropdown.js │ │ │ └── MenuDropdownMobile.js │ │ └── Modal │ │ │ └── index.js │ ├── containers │ │ ├── LayoutContainer │ │ │ └── LayoutContainer.js │ │ └── Page │ │ │ └── Page.js │ ├── index.js │ ├── providers │ │ ├── Menu │ │ │ ├── Context.js │ │ │ ├── Provider.js │ │ │ ├── index.js │ │ │ ├── store │ │ │ │ ├── actions.js │ │ │ │ ├── reducer.js │ │ │ │ └── types.js │ │ │ └── with.js │ │ ├── Modal │ │ │ ├── Context.js │ │ │ ├── Provider.js │ │ │ ├── index.js │ │ │ ├── store │ │ │ │ ├── actions.js │ │ │ │ ├── reducer.js │ │ │ │ └── types.js │ │ │ └── with.js │ │ └── Theme │ │ │ ├── Context.js │ │ │ ├── Provider.js │ │ │ ├── index.js │ │ │ └── with.js │ ├── styles │ │ └── custom-bootstrap.css │ └── utils │ │ └── theme.js └── tests │ ├── .eslintrc │ └── index.test.js ├── firebase-function-tools ├── .gitignore ├── .travis.yml ├── README.md ├── nwb.config.js ├── package-lock.json ├── package.json ├── src │ ├── counting.js │ ├── customClaims.js │ ├── index.js │ ├── load.js │ ├── notifications.js │ ├── thumbnail.js │ └── users.js └── tests │ ├── .eslintrc │ └── index-test.js ├── material-ui-shell ├── .gitignore ├── README.md ├── create-material-ui-shell │ ├── index.js │ ├── package.json │ └── template │ │ ├── .gitignore │ │ ├── index.html │ │ ├── jsconfig.json │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ │ ├── src │ │ ├── components │ │ │ ├── CustomPaper │ │ │ │ └── index.jsx │ │ │ └── Menu │ │ │ │ ├── MenuContent.jsx │ │ │ │ └── index.jsx │ │ ├── config │ │ │ ├── config.jsx │ │ │ ├── index.js │ │ │ ├── locales │ │ │ │ ├── de.js │ │ │ │ ├── en.js │ │ │ │ ├── index.js │ │ │ │ └── ru.js │ │ │ ├── menuItems.jsx │ │ │ ├── routes.jsx │ │ │ └── themes.js │ │ ├── demo-index.jsx │ │ └── pages │ │ │ ├── About │ │ │ └── index.jsx │ │ │ ├── DialogDemo │ │ │ └── index.jsx │ │ │ ├── FilterDemo │ │ │ ├── data.json │ │ │ └── index.jsx │ │ │ ├── Home │ │ │ └── index.jsx │ │ │ ├── LandingPage │ │ │ └── index.jsx │ │ │ ├── ListPageDemo │ │ │ ├── data.json │ │ │ └── index.jsx │ │ │ ├── MyAccount │ │ │ └── index.jsx │ │ │ ├── PageNotFound │ │ │ └── index.jsx │ │ │ ├── PasswordReset │ │ │ └── index.jsx │ │ │ ├── SignIn │ │ │ └── index.jsx │ │ │ ├── SignUp │ │ │ └── index.jsx │ │ │ ├── TabsDemo │ │ │ └── index.jsx │ │ │ └── ToastDemo │ │ │ └── index.jsx │ │ └── vite.config.js ├── cypress.config.ts ├── cypress │ ├── e2e │ │ └── spec.cy.js │ ├── fixtures │ │ └── example.json │ ├── screenshots │ │ └── spec.cy.js │ │ │ └── My React App -- renders app container top text (failed).png │ └── support │ │ ├── commands.js │ │ └── e2e.js ├── demo.jsx ├── index.html ├── package.json ├── src │ ├── common.type.ts │ ├── components │ │ ├── FilterDrawer │ │ │ └── index.tsx │ │ ├── Loading │ │ │ └── index.tsx │ │ ├── MenuHeader │ │ │ └── index.tsx │ │ ├── QuestionDialog │ │ │ └── index.tsx │ │ ├── Scrollbar │ │ │ └── index.tsx │ │ ├── SearchField │ │ │ └── index.tsx │ │ ├── UpdateDialog │ │ │ └── index.tsx │ │ └── index.ts │ ├── containers │ │ ├── ImageUploadDialog │ │ │ ├── getCropImage.tsx │ │ │ └── index.tsx │ │ ├── LayoutContainer │ │ │ └── index.tsx │ │ ├── Menu │ │ │ └── index.tsx │ │ ├── ResponsiveMenu │ │ │ └── index.tsx │ │ ├── SelectableMenuList │ │ │ └── index.tsx │ │ ├── UpdateContainer │ │ │ └── index.tsx │ │ ├── VirtualList │ │ │ └── index.tsx │ │ └── index.ts │ ├── index.ts │ ├── pages │ │ ├── LandingPage │ │ │ └── index.tsx │ │ ├── ListPage │ │ │ └── index.tsx │ │ ├── Page │ │ │ └── index.tsx │ │ ├── PageNotFound │ │ │ └── index.tsx │ │ └── index.ts │ ├── providers │ │ ├── Dialogs │ │ │ └── Question │ │ │ │ ├── Context.tsx │ │ │ │ ├── Provider.tsx │ │ │ │ └── index.tsx │ │ ├── Filter │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ ├── fields │ │ │ │ ├── boolean.tsx │ │ │ │ ├── date.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── number.tsx │ │ │ │ ├── text.tsx │ │ │ │ └── time.tsx │ │ │ ├── index.tsx │ │ │ └── store │ │ │ │ ├── actions.tsx │ │ │ │ ├── reducer.tsx │ │ │ │ ├── selectors.tsx │ │ │ │ └── types.tsx │ │ ├── Menu │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ ├── index.tsx │ │ │ └── store │ │ │ │ ├── actions.tsx │ │ │ │ ├── reducer.tsx │ │ │ │ └── types.tsx │ │ ├── Theme │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── VirtualLists │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ └── index.ts │ └── utils │ │ └── index.ts ├── tsconfig.json └── vite.config.ts └── rmw-shell ├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── create-rmw-shell ├── index.js ├── package.json └── template │ ├── .firebaserc │ ├── .gitignore │ ├── firebase.json │ ├── firebase │ ├── database.rules.json │ ├── firestore.indexes.json │ ├── firestore.rules │ ├── functions │ │ ├── .gitignore │ │ ├── auth │ │ │ ├── onCreate.f.js │ │ │ └── onDelete.f.js │ │ ├── db │ │ │ ├── admins │ │ │ │ └── onWrite.f.js │ │ │ ├── groupChatMessages │ │ │ │ └── onCreate.f.js │ │ │ ├── groupChats │ │ │ │ ├── members │ │ │ │ │ ├── onCreate.f.js │ │ │ │ │ └── onDelete.f.js │ │ │ │ └── name │ │ │ │ │ └── onUpdate.f.js │ │ │ ├── publicChats │ │ │ │ └── onCreate.f.js │ │ │ ├── roleGrants │ │ │ │ └── onWrite.f.js │ │ │ ├── roles │ │ │ │ └── onWrite.f.js │ │ │ ├── triggers │ │ │ │ └── onCreate.f.js │ │ │ ├── userChatMessages │ │ │ │ ├── onCreate.f.js │ │ │ │ └── onUpdate.f.js │ │ │ ├── userGrants │ │ │ │ └── onWrite.f.js │ │ │ ├── userRoles │ │ │ │ └── onWrite.f.js │ │ │ ├── users │ │ │ │ └── onWrite.f.js │ │ │ └── usersCount │ │ │ │ └── onDelete.f.js │ │ ├── gitignore │ │ ├── https │ │ │ ├── admin │ │ │ │ └── onCall.f.js │ │ │ ├── api │ │ │ │ ├── companies │ │ │ │ │ └── onRequest.f.js │ │ │ │ └── users │ │ │ │ │ └── onRequest.f.js │ │ │ ├── messages │ │ │ │ └── onCall.f.js │ │ │ └── usersSync │ │ │ │ └── onCall.f.js │ │ ├── index.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── storage │ │ │ ├── onFinalize.f.js │ │ │ └── thumbnails.js │ │ └── utils │ │ │ ├── customClaims.js │ │ │ ├── splitStringToArray.js │ │ │ └── users.js │ └── storage.rules │ ├── index.html │ ├── jsconfig.json │ ├── package.json │ ├── public │ ├── 404.svg │ ├── background.webp │ ├── bottom.jpg │ ├── favicon.ico │ ├── firebase-messaging-sw.js │ ├── firebase.png │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ ├── maskable_icon.png │ ├── material-ui.png │ ├── react.png │ ├── rmw.svg │ └── robots.txt │ ├── src │ ├── components │ │ ├── Forms │ │ │ ├── Company.jsx │ │ │ └── Task.jsx │ │ └── Menu │ │ │ └── MenuContent.jsx │ ├── config │ │ ├── config.jsx │ │ ├── getDefaultRoutes.jsx │ │ ├── grants.jsx │ │ ├── index.jsx │ │ ├── locales │ │ │ ├── de.js │ │ │ ├── en.js │ │ │ ├── index.js │ │ │ └── ru.js │ │ ├── menuItems.jsx │ │ ├── routes.jsx │ │ └── themes.jsx │ ├── containers │ │ └── Reports │ │ │ ├── Days.jsx │ │ │ ├── Months.jsx │ │ │ └── Providers.jsx │ ├── demo-index.jsx │ ├── index.html │ ├── pages │ │ ├── About │ │ │ └── index.jsx │ │ ├── Dashboard │ │ │ └── index.jsx │ │ ├── Demo │ │ │ ├── Admin │ │ │ │ └── index.jsx │ │ │ ├── Companies │ │ │ │ ├── Company.jsx │ │ │ │ └── index.jsx │ │ │ └── Tasks │ │ │ │ ├── Task.jsx │ │ │ │ └── index.jsx │ │ ├── Firebase │ │ │ ├── Cols.jsx │ │ │ ├── Docs.jsx │ │ │ ├── Lists.jsx │ │ │ ├── Messaging.jsx │ │ │ ├── Paths.jsx │ │ │ └── Storage.jsx │ │ ├── LandingPage │ │ │ ├── Footer.jsx │ │ │ ├── PageContent.jsx │ │ │ ├── index.jsx │ │ │ └── messages │ │ │ │ ├── bs.json │ │ │ │ ├── de.json │ │ │ │ ├── en.json │ │ │ │ ├── es.json │ │ │ │ ├── fr.json │ │ │ │ ├── index.js │ │ │ │ ├── it.json │ │ │ │ ├── pt.json │ │ │ │ └── ru.json │ │ ├── PageNotFound │ │ │ ├── 404.svg │ │ │ └── index.jsx │ │ └── Search │ │ │ └── index.jsx │ ├── service-worker.js │ └── serviceWorkerRegistration.js │ └── vite.config.js ├── cypress.config.js ├── cypress ├── e2e │ └── spec.cy.js ├── fixtures │ └── example.json └── support │ ├── commands.js │ └── e2e.js ├── index.html ├── package.json ├── src ├── components │ ├── ChatMessage │ │ └── index.tsx │ ├── FormFields │ │ ├── Autocomplete.tsx │ │ ├── AvatarImage.tsx │ │ ├── DatePicker.tsx │ │ ├── KeyboardDatePicker.tsx │ │ ├── TextField.tsx │ │ ├── Util.tsx │ │ └── index.tsx │ ├── Forms │ │ ├── Role.tsx │ │ └── index.tsx │ ├── Icons │ │ ├── FacebookIcon.tsx │ │ ├── GitHubIcon.tsx │ │ ├── GoogleIcon.tsx │ │ ├── RMWIcon.tsx │ │ ├── ReduxIcon.tsx │ │ ├── TwitterIcon.tsx │ │ └── index.tsx │ ├── SnackMessage │ │ └── index.tsx │ ├── UserRow │ │ └── index.tsx │ └── index.ts ├── containers │ ├── AuthUI │ │ └── index.tsx │ ├── Chat │ │ ├── Input.tsx │ │ └── index.tsx │ ├── Firebase │ │ ├── From.tsx │ │ └── index.tsx │ ├── GrantsList │ │ └── index.tsx │ ├── ImageUploadDialog │ │ ├── getCropImage.tsx │ │ └── index.tsx │ ├── ImageViewer │ │ └── index.tsx │ ├── Layout │ │ └── index.tsx │ ├── Page │ │ ├── FormPage.tsx │ │ ├── ListPage.tsx │ │ ├── MarkdownPage.tsx │ │ └── index.tsx │ ├── ResponsiveMenu │ │ └── index.tsx │ ├── RolesList │ │ └── index.tsx │ └── index.ts ├── index.ts ├── pages │ ├── Chats │ │ └── index.tsx │ ├── CreateChat │ │ └── index.tsx │ ├── EditAdmins │ │ └── index.tsx │ ├── EditMembers │ │ └── index.tsx │ ├── GroupChat │ │ └── index.tsx │ ├── MyAccount │ │ └── index.tsx │ ├── Roles │ │ ├── Role.tsx │ │ └── index.tsx │ ├── SignIn │ │ └── index.tsx │ ├── Users │ │ ├── User.tsx │ │ └── index.tsx │ └── index.ts ├── providers │ ├── Firebase │ │ ├── Cols │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Docs │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Lists │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Messaging │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ ├── Paths │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ │ └── Storage │ │ │ ├── Context.tsx │ │ │ ├── Provider.tsx │ │ │ └── index.tsx │ └── index.ts └── utils │ ├── auth.tsx │ ├── index.ts │ ├── locale.tsx │ └── location.tsx ├── tests ├── .eslintrc └── index.test.js ├── tsconfig.json └── vite.config.ts /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["react-app"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitbook/assets/screenshot-2021-09-22-211556.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/.gitbook/assets/screenshot-2021-09-22-211556.png -------------------------------------------------------------------------------- /.gitbook/assets/spaces_gitbook_avatar-rectangle (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/.gitbook/assets/spaces_gitbook_avatar-rectangle (1).png -------------------------------------------------------------------------------- /.gitbook/assets/spaces_gitbook_avatar-rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/.gitbook/assets/spaces_gitbook_avatar-rectangle.png -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Use Node.js 13 | uses: actions/setup-node@v4 14 | with: 15 | node-version: "20" 16 | - name: Install dependencies 17 | run: npm ci 18 | - name: Run tests 19 | run: npx lerna run test:package --since master 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | npm-debug.log* 3 | .dccache 4 | .DS_Store 5 | lerna-dubug.log 6 | .npmrc 7 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= v4 must be installed. 4 | 5 | ## Installation 6 | 7 | - Running `npm install` in the components's root directory will install everything you need for development. 8 | 9 | ## Demo Development Server 10 | 11 | - `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading. 12 | 13 | ## Running Tests 14 | 15 | - `npm test` will run the tests once. 16 | 17 | - `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`. 18 | 19 | - `npm run test:watch` will run the tests on every change. 20 | 21 | ## Building 22 | 23 | - `npm run build` will build the component for publishing to npm and also bundle the demo app. 24 | 25 | - `npm run clean` will delete built resources. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Tarik Huber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [React Most Wanted](README.md) 4 | * [Concept](concept.md) 5 | * [Getting started](getting-started.md) 6 | 7 | -------------------------------------------------------------------------------- /base-tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "jsx": "react-jsx", 17 | "declaration": true, 18 | "emitDeclarationOnly": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /concept.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: >- 3 | React Most Wanted uses a Layer based concept. Each layer has its own 4 | functionality and every layer above uses the features of the one below. 5 | --- 6 | 7 | # Concept 8 | 9 | React Most Wanted is based on **3 layers/shells**: 10 | 11 | * **base-shell** - The base for every RMW project. It includes the management of the \`Auth\` state, Internationalization state, the basic UI Layout, and the routing. 12 | * **mui-shell** - This layer includes Material-UI design into the base-shell with handy components like Page, a responsive Menu, and settings for language. 13 | * **rmw-shell** - This layer includes all the features from the previous ones and adds integration to Firebase by providing handy tools to kick start a new React project with the full power of Firebase. 14 | 15 | ![](.gitbook/assets/screenshot-2021-09-22-211556.png) 16 | 17 | -------------------------------------------------------------------------------- /getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Each shell has its own package and template. 3 | --- 4 | 5 | # Getting started 6 | 7 | ## base-shell 8 | 9 | Creating a **shell** starter kit is a fairly straight forward process: 10 | 11 | ``` 12 | npx create-react-app my-app --template base 13 | ``` 14 | 15 | ## mui-shell 16 | 17 | ```text 18 | npx create-react-app my-app --template material-ui 19 | ``` 20 | 21 | ## rmw-shell 22 | 23 | ```text 24 | npx create-react-app my-app --template rmw 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "version": "independent", 4 | "command": { 5 | "publish": { 6 | "gitReset": false 7 | } 8 | }, 9 | "packages": [ 10 | "packages/base-shell", 11 | "packages/base-shell/create-base-shell", 12 | "packages/base-shell/create-base-shell/template", 13 | "packages/material-ui-shell", 14 | "packages/material-ui-shell/create-material-ui-shell", 15 | "packages/material-ui-shell/create-material-ui-shell/template", 16 | "packages/rmw-shell", 17 | "packages/rmw-shell/create-rmw-shell", 18 | "packages/rmw-shell/create-rmw-shell/template" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/rmw-shell", 6 | "packages/material-ui-shell", 7 | "packages/base-shell" 8 | ], 9 | "devDependencies": { 10 | "lerna": "^8.1.8" 11 | }, 12 | "optionalDependencies": { 13 | "@rollup/rollup-linux-x64-gnu": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/base-shell/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /node_modules 3 | npm-debug.log* 4 | dist/ 5 | stats.html 6 | -------------------------------------------------------------------------------- /packages/base-shell/README.md: -------------------------------------------------------------------------------- 1 | # base-shell 2 | 3 | **[Base shell](./packages/base-shell/)**: 4 | the basic react setup: routing, internationalization and async load. 5 | 6 | `npx create-react-app my-app --template base` 7 | 8 | . 9 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ecronix/create-base-shell", 3 | "version": "1.0.42", 4 | "description": "A template to create new projects based on @ecronix/base-shell", 5 | "bin": { 6 | "create-my-template": "index.js" 7 | }, 8 | "main": "index.js", 9 | "devDependencies": { 10 | "base-shell-template": "^1.0.39" 11 | }, 12 | "scripts": { 13 | "start": "node index.js" 14 | }, 15 | "keywords": [ 16 | "ecronix", 17 | "base-shell", 18 | "react-most-wanted" 19 | ], 20 | "author": "Abdallah", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/.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 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | firebase-debug.log* -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with `@ecronix/base-shell` 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm run dev` 8 | 9 | ### `npm run build` 10 | 11 | ### `npm run serve` 12 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-shell-template", 3 | "version": "1.0.39", 4 | "description": "This project was bootstrapped with [@ecronix/base-shell](https://github.com/ecronix/react-most-wanted)", 5 | "private": "true", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "serve": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@ecronix/base-shell": "^2.6.63" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^4", 17 | "vite": "^5" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "ISC" 22 | } 23 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/base-shell/create-base-shell/template/public/favicon.ico -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/base-shell/create-base-shell/template/public/logo192.png -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/base-shell/create-base-shell/template/public/logo512.png -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "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 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/defaultRoutes.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const getDefaultRoutes = (appConfig) => { 4 | const { pages } = appConfig || {} 5 | const { PageNotFound = () =>
Page not found
} = pages || {} 6 | 7 | return [{ path: '*', element: }] 8 | } 9 | 10 | export default getDefaultRoutes 11 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/index.js: -------------------------------------------------------------------------------- 1 | export { default } from "./config"; 2 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/locales/de.js: -------------------------------------------------------------------------------- 1 | const messages = { 2 | sign_in: 'Anmelden', 3 | sign_out: 'Abmelden', 4 | username: 'Nutzername', 5 | password: 'Passwort', 6 | about: 'Über', 7 | home: 'Startseite', 8 | page_not_found: 'Seite nicht gefunden', 9 | settings: 'Einstellungen', 10 | language: 'Sprache', 11 | en: 'Englisch', 12 | de: 'Deutsch', 13 | ru: 'Russisch', 14 | } 15 | 16 | export default messages 17 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/locales/en.js: -------------------------------------------------------------------------------- 1 | const messages = { 2 | sign_in: 'Sign in', 3 | sign_out: 'Sign out', 4 | username: 'Username', 5 | password: 'Password', 6 | about: 'About', 7 | home: 'Home', 8 | page_not_found: 'Page not found', 9 | settings: 'Settings', 10 | language: 'Language', 11 | en: 'English', 12 | de: 'German', 13 | ru: 'Russian', 14 | } 15 | 16 | export default messages 17 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/locales/index.js: -------------------------------------------------------------------------------- 1 | const locales = [ 2 | { 3 | locale: 'en', 4 | messages: import('./en'), 5 | }, 6 | { 7 | locale: 'ru', 8 | messages: import('./ru'), 9 | }, 10 | { 11 | locale: 'de', 12 | messages: import('./de'), 13 | }, 14 | ] 15 | 16 | export default locales 17 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/locales/ru.js: -------------------------------------------------------------------------------- 1 | const messages = { 2 | sign_in: 'Вход', 3 | sign_out: 'Выход', 4 | username: 'Имя пользователя', 5 | password: 'Пароль', 6 | about: 'О нас', 7 | home: 'Главная', 8 | page_not_found: 'Страница не найдена', 9 | settings: 'Настройки', 10 | language: 'Язык', 11 | en: 'English', 12 | de: 'Deutsch', 13 | ru: 'Русский', 14 | } 15 | 16 | export default messages 17 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/config/routes.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AuthorizedRoute, UnauthorizedRoute } from "@ecronix/base-shell"; 3 | import { SignInPage } from "../pages/SignIn"; 4 | import { HomePage } from "../pages/Home"; 5 | import { AboutPage } from "../pages/About"; 6 | 7 | const routes = [ 8 | { 9 | path: "/signin", 10 | exact: true, 11 | element: ( 12 | 13 | 14 | 15 | ), 16 | }, 17 | { path: "/about", exact: true, element: }, 18 | { 19 | path: "/home", 20 | exact: true, 21 | element: ( 22 | 23 | 24 | 25 | ), 26 | }, 27 | ]; 28 | 29 | export default routes; 30 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/demo-index.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import { AppContainer } from "@ecronix/base-shell"; 4 | import config from "./config"; 5 | 6 | createRoot(document.getElementById("root")).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/pages/About/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useIntl } from "react-intl"; 3 | 4 | export const AboutPage = () => { 5 | const intl = useIntl(); 6 | return
{intl.formatMessage({ id: "about" })}
; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/pages/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useIntl } from "react-intl"; 3 | import { useSimpleValues, useOnline } from "@ecronix/base-shell"; 4 | 5 | export const HomePage = () => { 6 | const intl = useIntl(); 7 | const isOnline = useOnline(); 8 | const { setValue, getValue, clearAll } = useSimpleValues(); 9 | 10 | const simpleNValueKey = "nkey"; 11 | const simplePValueKey = "pKey"; 12 | 13 | return ( 14 |
15 | Non persistent: {getValue(simpleNValueKey, "empty")} 16 |
17 |
18 | Persistent: {getValue(simplePValueKey, "empty")} 19 |
20 | {isOnline ? "online" : "offline"} 21 |
22 |
23 | 30 |
31 |
32 | 39 |
40 |
41 | 51 |
52 | {intl.formatMessage({ id: "home" })} 53 |
54 |
55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/pages/LandingPage/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | 4 | export const LandingPage = () => { 5 | return ( 6 |
7 | Landing Page 8 |
9 | Home 10 |
11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/src/pages/PageNotFound/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useIntl } from "react-intl"; 3 | 4 | export const PageNotFound = () => { 5 | const intl = useIntl(); 6 | return
{intl.formatMessage({ id: "page_not_found" })}
; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/base-shell/create-base-shell/template/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/base-shell/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | setupNodeEvents(on, config) { 6 | // implement node event listeners here 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/base-shell/cypress/e2e/spec.cy.js: -------------------------------------------------------------------------------- 1 | describe("My React App", () => { 2 | beforeEach(() => { 3 | cy.visit("http://localhost:5173"); 4 | }); 5 | 6 | it("renders the app", () => { 7 | cy.get("#root").should("exist"); 8 | }); 9 | 10 | it('renders "app container top" text', () => { 11 | cy.contains("App Container top").should("exist"); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/base-shell/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /packages/base-shell/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -------------------------------------------------------------------------------- /packages/base-shell/cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') -------------------------------------------------------------------------------- /packages/base-shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/base-shell/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { AuthorizedRoute } from "./AuthorizedRoute"; 2 | export { UnauthorizedRoute } from "./UnauthorizedRoute"; 3 | -------------------------------------------------------------------------------- /packages/base-shell/src/containers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Layout"; 2 | export * from "./App"; 3 | -------------------------------------------------------------------------------- /packages/base-shell/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components"; 2 | export * from "./containers"; 3 | export * from "./utils"; 4 | export * from "./providers"; 5 | 6 | declare global { 7 | interface Window { 8 | update?: () => void; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/AddToHomeScreen/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { AddToHomeScreenStateProps } from "./Provider"; 3 | export interface AddToHomeScreenContextType { 4 | deferredPrompt?: Event | undefined; 5 | isAppInstallable?: boolean; 6 | isAppInstalled?: boolean; 7 | 8 | /** 9 | * @description Updates addToHomeScreenContext with provided data 10 | * @param {AddToHomeScreenStateProps} 11 | */ 12 | setA2HPState: React.Dispatch>; 13 | } 14 | 15 | const Context = React.createContext( 16 | undefined 17 | ); 18 | 19 | export default Context; 20 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/AddToHomeScreen/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Context from "./Context"; 3 | 4 | const initialState: AddToHomeScreenStateProps = { 5 | deferredPrompt: undefined, 6 | isAppInstallable: false, 7 | isAppInstalled: false, 8 | }; 9 | 10 | export type AddToHomeScreenStateProps = { 11 | deferredPrompt?: Event | undefined; 12 | isAppInstallable?: boolean; 13 | isAppInstalled?: boolean; 14 | }; 15 | 16 | const Provider: React.FC<{ children: React.ReactNode }> = ({ children }) => { 17 | const [state, setA2HPState] = 18 | useState(initialState); 19 | 20 | window.addEventListener("beforeinstallprompt", (e) => { 21 | // Prevent Chrome 67 and earlier from automatically showing the prompt 22 | e.preventDefault(); 23 | // Stash the event so it can be triggered later. 24 | setA2HPState({ deferredPrompt: e, isAppInstallable: true }); 25 | }); 26 | 27 | window.addEventListener("appinstalled", (evt) => { 28 | setA2HPState({ isAppInstalled: true }); 29 | }); 30 | 31 | return ( 32 | 33 | {children} 34 | 35 | ); 36 | }; 37 | 38 | export default Provider; 39 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/AddToHomeScreen/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import Context, { AddToHomeScreenContextType } from "./Context"; 3 | import Provider from "./Provider"; 4 | 5 | /** 6 | * Custom hook for addToHomeScreenContext 7 | * 8 | * @function 9 | * @returns {AddToHomeScreenContext} The locale context value. 10 | * @throws {Error} If used outside of AddToHomeScreenProvider 11 | * @example 12 | * const a2HSContext = useAddToHomeScreen(); 13 | * 14 | * @description 15 | * This hook provides access to AddToHomeScreenContext. 16 | * 17 | * @see {@link AddToHomeScreenContextType} for the shape of the returned context 18 | */ 19 | function useAddToHomeScreen(): AddToHomeScreenContextType { 20 | const context = useContext(Context); 21 | if (!context) { 22 | throw new Error( 23 | "useAddToHomeScreen must be used within a AddToHomeScreenProvider" 24 | ); 25 | } 26 | return context; 27 | } 28 | 29 | export { 30 | useAddToHomeScreen, 31 | Context as AddToHomeScreenContext, 32 | Provider as AddToHomeScreenProvider, 33 | }; 34 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Auth/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export type ProviderData = { providerId: string }; 4 | export type AuthUser = { 5 | isAuthenticated: boolean; 6 | photoURL: string; 7 | displayName: string; 8 | email: string; 9 | uid: string; 10 | isAdmin?: boolean; 11 | providerData?: ProviderData[]; 12 | notificationsDisabled?: boolean; 13 | grants?: string[]; 14 | }; 15 | 16 | // TODO Fix isAuthGranted import everywhere 17 | export interface IAuthContext { 18 | /** 19 | * @description Authorized user object 20 | */ 21 | auth: AuthUser; 22 | 23 | /** 24 | * @description Set auth to provided auth parameter 25 | * @param auth 26 | */ 27 | setAuth: (auth: any) => void; 28 | 29 | /** 30 | * @description Update auth to provided auth parameter 31 | * @param auth 32 | */ 33 | updateAuth: (auth: any) => void; 34 | 35 | isAuthGranted?: (auth: AuthUser, type: string) => boolean; 36 | } 37 | 38 | const ConfigContext = React.createContext(undefined); 39 | 40 | export default ConfigContext; 41 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Auth/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer } from "react"; 2 | import Context from "./Context"; 3 | 4 | type ReducerAction = { 5 | type: string; 6 | auth: any; 7 | }; 8 | 9 | function reducer(state: any, action: ReducerAction) { 10 | const { type, auth } = action; 11 | switch (type) { 12 | case "SET_AUTH": 13 | return auth; 14 | case "UPDATE_AUTH": 15 | return { ...state, ...auth }; 16 | default: 17 | throw new Error(); 18 | } 19 | } 20 | 21 | const Provider: React.FC<{ 22 | children: React.ReactNode; 23 | persistKey: string; 24 | }> = ({ persistKey = "auth", children }) => { 25 | const persistAuth = JSON.parse( 26 | localStorage.getItem(persistKey)?.replace("undefined", "{}") || "{}" 27 | ); 28 | 29 | const [auth, dispatch] = useReducer(reducer, persistAuth || {}); 30 | 31 | useEffect(() => { 32 | try { 33 | localStorage.setItem(persistKey, JSON.stringify(auth)); 34 | } catch (error) { 35 | console.warn(error); 36 | } 37 | }, [auth, persistKey]); 38 | 39 | const setAuth = (auth: any) => { 40 | dispatch({ type: "SET_AUTH", auth }); 41 | }; 42 | 43 | const updateAuth = (auth: any) => { 44 | dispatch({ type: "UPDATE_AUTH", auth }); 45 | }; 46 | 47 | return ( 48 | 49 | {children} 50 | 51 | ); 52 | }; 53 | 54 | export default Provider; 55 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Auth/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import Context, { IAuthContext } from "./Context"; 3 | import Provider from "./Provider"; 4 | /** 5 | * Custom hook to access the authentication context. 6 | * 7 | * @function 8 | * @returns {IAuthContext} The authentication context value. 9 | * @throws {Error} If used outside of an AuthProvider. 10 | * @example 11 | * const auth = useAuth(); 12 | * console.log(auth.isAuthenticated); 13 | * 14 | * @description 15 | * This hook provides access to the authentication context, which includes 16 | * information about the current user's authentication state and related 17 | * functions. It must be used within a component that is wrapped by an 18 | * AuthProvider. 19 | * 20 | * The IAuthContext typically includes properties such as: 21 | * - isAuthenticated: A boolean indicating if the user is authenticated 22 | * - user: The current user object (if authenticated) 23 | * - login: A function to log in the user 24 | * - logout: A function to log out the user 25 | * 26 | * @see {@link IAuthContext} for the shape of the returned context 27 | */ 28 | function useAuth(): IAuthContext { 29 | const context = useContext(Context); 30 | 31 | if (context === undefined) { 32 | throw new Error("useAuth must be used within a AuthProvider"); 33 | } 34 | 35 | return context; 36 | } 37 | 38 | export { useAuth, Context as AuthContext, Provider as AuthProvider }; 39 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Config/Context.tsx: -------------------------------------------------------------------------------- 1 | import { AppConfig } from "@ecronix/base-shell"; 2 | import React from "react"; 3 | 4 | export interface ConfigContextType { 5 | /** 6 | * @description App configuration 7 | */ 8 | appConfig: AppConfig; 9 | } 10 | 11 | const ConfigContext = React.createContext( 12 | undefined 13 | ); 14 | 15 | export default ConfigContext; 16 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Config/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from "react"; 2 | import Context from "./Context"; 3 | import { AppConfig } from "@ecronix/base-shell"; 4 | 5 | interface ProviderProps { 6 | appConfig: AppConfig; 7 | children: ReactNode; 8 | } 9 | 10 | const Provider: React.FC = ({ appConfig, children }) => { 11 | return {children}; 12 | }; 13 | 14 | export default Provider; 15 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Config/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import Context, { ConfigContextType } from "./Context"; 3 | import Provider from "./Provider"; 4 | 5 | /** 6 | * Custom hook to access the config provider 7 | * 8 | * @function 9 | * @returns {ConfigContextType} The configuration context. 10 | * @throws {Error} If used outside of an ConfigProvider. 11 | * @example 12 | * const { appConfig } = useConfig(); 13 | * 14 | * @description 15 | * This hook provides access to the configuration context. It provides json object containing all configuration data 16 | * and must be used withing ConfigProvider 17 | * 18 | * @see {@link ConfigContextType} for the shape of the returned context 19 | */ 20 | function useConfig(): ConfigContextType { 21 | const context = useContext(Context); 22 | 23 | if (context === undefined) { 24 | throw new Error("useConfig must be used within a ConfigProvider"); 25 | } 26 | 27 | return context; 28 | } 29 | 30 | export { useConfig, Context as ConfigContext, Provider as ConfigProvider }; 31 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Locale/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export interface LocaleContextType { 4 | /** 5 | * Current locale settings - defaults to 'en' 6 | * @type {string} 7 | */ 8 | locale: string; 9 | 10 | /** 11 | * Method to update locale settings 12 | * @param {string} locale - New provided locale string 13 | */ 14 | setLocale: React.Dispatch>; 15 | } 16 | 17 | const Context = React.createContext(undefined); 18 | 19 | export default Context; 20 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Locale/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Context from "./Context"; 3 | 4 | export interface LocaleProviderProps { 5 | children: React.ReactNode; 6 | defaultLocale?: string; 7 | persistKey?: string; 8 | } 9 | 10 | const Provider: React.FC = ({ 11 | children, 12 | defaultLocale = "en", 13 | persistKey = "locale", 14 | }) => { 15 | const persistLocale = localStorage.getItem(persistKey); 16 | const [locale, setLocale] = useState(persistLocale || defaultLocale); 17 | 18 | useEffect(() => { 19 | try { 20 | localStorage.setItem(persistKey, locale); 21 | } catch (error) { 22 | console.warn(error); 23 | } 24 | }, [locale, persistKey]); 25 | 26 | return ( 27 | 28 | {children} 29 | 30 | ); 31 | }; 32 | 33 | export default Provider; 34 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Locale/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import Context, { LocaleContextType } from "./Context"; 3 | import Provider from "./Provider"; 4 | 5 | /** 6 | * Custom hook for accessing locale context 7 | * 8 | * @function 9 | * @returns {LocaleContextType} The locale context value. 10 | * @throws {Error} If used outside of LocaleContext 11 | * @example 12 | * const { setLocale, locale = "en" } = useLocale(); 13 | * 14 | * @description 15 | * This hook provides access localization context. It provides locale value and method to update locale value. 16 | * 17 | * @see {@link LocaleProvider} for providing localization context 18 | * @see {@link LocaleContextType} for the shape of the returned context 19 | */ 20 | function useLocale(): LocaleContextType { 21 | const context = useContext(Context); 22 | if (!context) { 23 | throw new Error("useLocale must be used within a LocaleProvider"); 24 | } 25 | return context; 26 | } 27 | 28 | export { useLocale, Context as LocaleContext, Provider as LocaleProvider }; 29 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Online/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Context = React.createContext(undefined); 4 | 5 | export default Context; 6 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Online/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import Context from "./Context"; 3 | 4 | export interface OnlineProviderProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | const Provider: React.FC = ({ children }) => { 9 | const [isOnline, setOnline] = useState(navigator.onLine); 10 | 11 | window.addEventListener("online", () => setOnline(true)); 12 | window.addEventListener("offline", () => setOnline(false)); 13 | 14 | return {children}; 15 | }; 16 | 17 | export default Provider; 18 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Online/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import Context from "./Context"; 3 | import Provider from "./Provider"; 4 | 5 | /** 6 | * Custom hook to access the online listener provider. 7 | * 8 | * @function 9 | * @returns {boolean} Boolean value regarding if client is online or offline 10 | * @throws {Error} If used outside of an OnlineProvider. 11 | * @example 12 | * const isOnline = useOnline(); 13 | * 14 | * @description 15 | * This hook provides access to the online listener context. It returns true if client is online. 16 | */ 17 | function useOnline(): boolean { 18 | const context = useContext(Context); 19 | if (!context) { 20 | throw new Error("useOnline must be used within a OnlineProvider"); 21 | } 22 | return context; 23 | } 24 | 25 | export { useOnline, Context as OnlineContext, Provider as OnlineProvider }; 26 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/SimpleValues/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export interface SimpleValuesContextType { 4 | /** 5 | * Sets a value in the context. 6 | * @param params - The parameters to set a value. 7 | * @param params.key - The key to identify the value. 8 | * @param params.value - The value to set. 9 | * @param boolean params.persist - Whether to persist the value (e.g., in local storage). Defaults to 'false'. 10 | */ 11 | setValue: (key: string, value: any, persist?: boolean) => void; 12 | 13 | /** 14 | * Gets a value from the context by key. 15 | * @param key - The key to retrieve the value for. 16 | * @returns The value corresponding to the key. 17 | */ 18 | getValue: (key: string, defaultValue?: any) => string; 19 | 20 | /** 21 | * Clears a value from the context by key. 22 | * @param key - The key to clear the value for. 23 | */ 24 | clearValue: (key: string) => void; 25 | 26 | /** 27 | * Clears all values from the context. 28 | */ 29 | clearAll: () => void; 30 | } 31 | 32 | const Context = React.createContext( 33 | undefined 34 | ); 35 | 36 | export default Context; 37 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/SimpleValues/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import Context, { SimpleValuesContextType } from "./Context"; 3 | import Provider from "./Provider"; 4 | /** 5 | * Custom hook to access the simple values context. 6 | * 7 | * @function 8 | * @returns {SimpleValuesContextType} The simple values context value. 9 | * @throws {Error} If used outside of an SimpleValuesProvider. 10 | * @example 11 | * const { setValue, getValue, clearAll, clearValue } = useSimpleValues(); 12 | * 13 | * @description 14 | * This hook provides access to the simple values context. It must be used inside SimpleValuesProvider. 15 | * It provides set of methods for manipulating values. 16 | * It provides following methods 17 | * - setValue 18 | * - getValue 19 | * - clearAll 20 | * - clearValue 21 | * 22 | * @see {@link SimpleValuesContextType} for the shape of the returned context 23 | */ 24 | function useSimpleValues(): SimpleValuesContextType { 25 | const context = useContext(Context); 26 | if (!context) { 27 | throw new Error( 28 | "useSimpleValues must be used within a SimpleValuesProvider" 29 | ); 30 | } 31 | return context; 32 | } 33 | 34 | export { 35 | useSimpleValues, 36 | Context as SimpleValuesContext, 37 | Provider as SimpleValuesProvider, 38 | }; 39 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Update/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export interface UpdateContextType { 4 | /** 5 | * @description Value indicating if update is available or not 6 | */ 7 | isUpdateAvailable: boolean; 8 | 9 | /** 10 | * @description Method for updating window 11 | * @param registration 12 | */ 13 | runUpdate: (registration: any) => void; 14 | } 15 | 16 | const Context = React.createContext(undefined); 17 | 18 | export default Context; 19 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Update/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import Context from "./Context"; 3 | 4 | const runUpdate = (registration: any) => { 5 | try { 6 | if (registration) { 7 | registration.waiting.postMessage({ type: "SKIP_WAITING" }); 8 | } 9 | if (window.update) { 10 | window.update && window.update(); 11 | } 12 | } catch (error) { 13 | console.log(error); 14 | } 15 | }; 16 | 17 | const Provider: React.FC<{ 18 | children: React.ReactNode; 19 | checkInterval: number; 20 | }> = ({ children, checkInterval }) => { 21 | const [isUpdateAvailable, setUpdateAvailable] = useState(false); 22 | 23 | const checkUpdate = () => { 24 | if (window.update) { 25 | setUpdateAvailable(true); 26 | } else { 27 | setUpdateAvailable(false); 28 | setTimeout(checkUpdate, checkInterval); 29 | } 30 | }; 31 | 32 | useEffect(checkUpdate, [checkUpdate]); 33 | 34 | return ( 35 | 36 | {children} 37 | 38 | ); 39 | }; 40 | 41 | export default Provider; 42 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/Update/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import Context, { UpdateContextType } from "./Context"; 3 | import Provider from "./Provider"; 4 | 5 | /** 6 | * Custom hook to access the update context. 7 | * 8 | * @function 9 | * @returns {UpdateContextType} The update context value. 10 | * @throws {Error} If used outside of an UpdateProvider. 11 | * 12 | * @description 13 | * This hook provides access to the update context. It must be used within UpdateProvider. 14 | * 15 | * 16 | * @see {@link UpdateContextType} for the shape of the returned context 17 | */ 18 | function useUpdate(): UpdateContextType { 19 | const context = useContext(Context); 20 | if (!context) { 21 | throw new Error("useUpdate must be used within a UpdateProvider"); 22 | } 23 | return context; 24 | } 25 | 26 | export { useUpdate, Context as UpdateContext, Provider as UpdateProvider }; 27 | -------------------------------------------------------------------------------- /packages/base-shell/src/providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Update"; 2 | export * from "./SimpleValues"; 3 | export * from "./Online"; 4 | export * from "./Locale"; 5 | export * from "./Config"; 6 | export * from "./Auth"; 7 | export * from "./AddToHomeScreen"; 8 | -------------------------------------------------------------------------------- /packages/base-shell/src/utils/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @function 3 | * @description Method for merging two different objects. It accepts 2 objects and returns new object. 4 | * @param {Record} obj1 First object 5 | * @param {Record} obj2 Second object 6 | * @returns New object created from merging provided objects 7 | */ 8 | export const merge = (obj1: Record, obj2: Record) => { 9 | let temp = { ...obj1, ...obj2 }; 10 | 11 | Object.keys(temp).forEach((key) => { 12 | if (typeof temp[key] === "object" && !(temp[key] instanceof Array)) { 13 | temp[key] = { ...obj1[key], ...obj2[key] }; 14 | } 15 | }); 16 | 17 | return temp; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/base-shell/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { merge } from "./config"; 2 | export * from "./locale"; 3 | -------------------------------------------------------------------------------- /packages/base-shell/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../base-tsconfig.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@ecronix/base-shell": ["./src"], 6 | "@ecronix/base-shell/*": ["./src/*"] 7 | }, 8 | "declarationDir": "./dist/types", 9 | }, 10 | "include": ["src/**/*"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/base-shell/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import path from "node:path"; 4 | import { visualizer } from "rollup-plugin-visualizer"; 5 | import { externalizeDeps } from "vite-plugin-externalize-deps"; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [react(), visualizer(), externalizeDeps()], 10 | resolve: { 11 | alias: { 12 | "@ecronix/base-shell": path.resolve(__dirname, "./src"), 13 | }, 14 | extensions: [".js", ".ts", ".jsx", ".tsx"], 15 | }, 16 | build: { 17 | minify: false, 18 | lib: { 19 | entry: path.resolve(__dirname, "./src/index.ts"), 20 | name: "base-shell", 21 | formats: ["es"], 22 | }, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | /es 4 | /lib 5 | /node_modules 6 | /umd 7 | npm-debug.log* 8 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 8 6 | 7 | before_install: 8 | - npm install codecov.io coveralls 9 | 10 | after_success: 11 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 12 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 13 | 14 | branches: 15 | only: 16 | - master 17 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:3000", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /packages/bootstrap-shell/README.md: -------------------------------------------------------------------------------- 1 | # material-ui-shell 2 | 3 | [![Travis][build-badge]][build] 4 | [![npm package][npm-badge]][npm] 5 | [![Coveralls][coveralls-badge]][coveralls] 6 | 7 | Describe material-ui-shell here. 8 | 9 | [build-badge]: https://img.shields.io/travis/user/repo/master.png?style=flat-square 10 | [build]: https://travis-ci.org/user/repo 11 | 12 | [npm-badge]: https://img.shields.io/npm/v/npm-package.png?style=flat-square 13 | [npm]: https://www.npmjs.org/package/npm-package 14 | 15 | [coveralls-badge]: https://img.shields.io/coveralls/user/repo/master.png?style=flat-square 16 | [coveralls]: https://coveralls.io/github/user/repo 17 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/README.md: -------------------------------------------------------------------------------- 1 | # cra-template-base-shell 2 | 3 | This is the base-shell template for [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | Use it like this: 6 | `npx create-react-app base-shell-app --template cra-template-base` 7 | 8 | For more information, please refer to: 9 | 10 | - [Getting Started](https://create-react-app.dev/docs/getting-started) – How to create a new app. 11 | - [User Guide](https://create-react-app.dev) – How to develop apps bootstrapped with Create React App. 12 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cra-template-bs", 3 | "version": "0.1.1", 4 | "keywords": [ 5 | "react", 6 | "create-react-app", 7 | "template", 8 | "bootstrap" 9 | ], 10 | "description": "The bootstrap template for Create React App.", 11 | "main": "template.json", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/TarikHuber/react-most-wanted", 15 | "directory": "packages/base-shell/cra-template-material-ui" 16 | }, 17 | "license": "MIT", 18 | "engines": { 19 | "node": ">=8" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/TarikHuber/react-most-wanted/issues" 23 | }, 24 | "files": [ 25 | "template", 26 | "template.json" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "package": { 3 | "dependencies": { 4 | "jss": "10.x", 5 | "jss-rtl": "0.x", 6 | "@formatjs/intl-relativetimeformat": "8.x", 7 | "base-shell": "1.x", 8 | "material-ui-shell": "2.x", 9 | "github-markdown-css": "4.x", 10 | "intl": "1.x", 11 | "intl-locales-supported": "1.x", 12 | "notistack": "2.x", 13 | "react": "17.x", 14 | "react-custom-scrollbars": "4.x", 15 | "react-dom": "17.x", 16 | "react-easy-crop": "3.x", 17 | "react-intl": "5.x", 18 | "react-ios-pwa-prompt": "1.x", 19 | "react-markdown": "7.x", 20 | "react-router-dom": "5.x", 21 | "react-virtualized-auto-sizer": "1.x", 22 | "react-window": "1.x", 23 | "@mui/material": "5.x", 24 | "@emotion/react": "11.x", 25 | "@emotion/styled": "11.x", 26 | "@mui/icons-material": "5.x", 27 | "bootstrap": "5.x", 28 | "react-bootstrap": "2.x", 29 | "react-bootstrap-icons": "1.x" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "7.x", 33 | "@types/react": "17.x", 34 | "typescript": "4.x" 35 | }, 36 | "eslintConfig": { 37 | "extends": ["react-app", "react-app/jest"] 38 | } 39 | } 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/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 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | firebase-debug.log* -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/bootstrap-shell/cra-template-bs/template/public/favicon.ico -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/bootstrap-shell/cra-template-bs/template/public/logo192.png -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/bootstrap-shell/cra-template-bs/template/public/logo512.png -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "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 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import App from 'base-shell/lib' 3 | import _config from './config' 4 | export default class Demo extends Component { 5 | render() { 6 | return 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/components/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function Loading() { 4 | return
Loading
5 | } 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/components/Loading/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as BS from 'react-bootstrap' 3 | 4 | export default function CircularIndeterminate() { 5 | return ( 6 |
18 | 19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/components/Menu/MenuRight.js: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react' 3 | import * as BS from "react-bootstrap" 4 | import { BsFacebook, BsInstagram, BsGithub } from "react-icons/bs"; 5 | 6 | export default function MenuRight() { 7 | return (<> 8 | Hallo 9 | 10 | 11 | 12 | Download 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/config.js: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react' 2 | import routes from './routes' 3 | import parseLanguages from 'base-shell/lib/utils/locale' 4 | import locales from './locales' 5 | import React from 'react' 6 | import menuItems from './menuItems' 7 | 8 | const Loading = () =>
Loading...
9 | 10 | const config = { 11 | containers: { 12 | LayoutContainer: lazy(() => 13 | import('bootstrap-shell/lib/containers/LayoutContainer/LayoutContainer') 14 | ), 15 | }, 16 | components: { 17 | Loading, 18 | }, 19 | auth: { 20 | signInURL: '/signin', 21 | }, 22 | pwa: { 23 | useiOSPWAPrompt: true, 24 | iOSPWAPromptProps: {}, 25 | }, 26 | routes, 27 | locale: { 28 | locales, 29 | defaultLocale: parseLanguages(['en', 'de', 'ru'], 'en'), 30 | onError: (e) => { 31 | //console.warn(e) 32 | return 33 | }, 34 | }, 35 | menu: { 36 | width: 240, 37 | initialMobileMenuOpen: false, 38 | MenuRight: lazy(() => import('../components/Menu/MenuRight')), 39 | menuItems, 40 | }, 41 | theme: {}, 42 | pages: { 43 | // The LandingPage is completely separeted from the App and is not under the LayoutContainer 44 | LandingPage: lazy(() => import('../pages/LandingPage')), 45 | PageNotFound: lazy(() => import('../pages/PageNotFound/PageNotFound')), 46 | }, 47 | } 48 | 49 | export default config 50 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/dark.scss: -------------------------------------------------------------------------------- 1 | $theme-colors: ( 2 | 'info': tomato, 3 | 'danger': teal, 4 | ); 5 | 6 | @import '~bootstrap/scss/bootstrap'; 7 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './config.js' 2 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/locales/index.js: -------------------------------------------------------------------------------- 1 | const locales = [ 2 | { 3 | locale: 'en', 4 | messages: import('./en'), 5 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/en`), 6 | }, 7 | { 8 | locale: 'ru', 9 | messages: import('./ru'), 10 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/ru`), 11 | }, 12 | { 13 | locale: 'de', 14 | messages: import('./de'), 15 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/de`), 16 | }, 17 | ] 18 | 19 | export default locales 20 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/menuItems.js: -------------------------------------------------------------------------------- 1 | const menuItems = [ 2 | /* 3 | { 4 | path: '/', 5 | displayName: 'Home', 6 | disabled: true, 7 | disabledMobile: false, 8 | }, 9 | { 10 | path: '/', 11 | displayName: 'Dropdown with Link', 12 | disabled: true, 13 | disabledMobile: false, 14 | nested: [ 15 | 16 | ] 17 | }, 18 | */ 19 | { 20 | displayName: 'Dropdown', 21 | disabled: false, 22 | nested: [ 23 | { 24 | path: '/home', 25 | displayName: 'Home', 26 | disabled: false, 27 | }, 28 | { 29 | displayName: 'Demo Pages', 30 | disabled: false, 31 | nested: [ 32 | { 33 | path: '/dialog', 34 | displayName: 'Dialog Demo', 35 | disabled: false, 36 | }, 37 | ] 38 | }, 39 | ] 40 | } 41 | ] 42 | 43 | export default menuItems; -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/routes.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/jsx-key */ 2 | import React, { lazy } from 'react' 3 | //import AuthorizedRoute from 'base-shell/lib/components/AuthorizedRoute' 4 | //import UnauthorizedRoute from 'base-shell/lib/components/UnauthorizedRoute' 5 | 6 | const Home = lazy(() => import('../pages/Home/Home')) 7 | const Dialog = lazy(() => import('../pages/DialogDemo')) 8 | const routes = [ 9 | { 10 | path: '/home', // root path 11 | exact: true, 12 | element: , 13 | }, 14 | { 15 | path: '/dialog', // path /home2 16 | exact: true, 17 | element: , 18 | }, 19 | { 20 | path: '*', //Page not found 21 | exact: true, 22 | element: , 23 | }, 24 | ] 25 | 26 | export default routes 27 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/config/themes.js: -------------------------------------------------------------------------------- 1 | import red from '@mui/material/colors/red' 2 | 3 | const themes = [ 4 | { 5 | id: 'default', 6 | }, 7 | { 8 | id: 'dark', 9 | white: 'text-white', 10 | source: { 11 | bg: 'dark', 12 | bgColor: 'bg-dark', 13 | palette: { 14 | primary: white, 15 | secondary: white, 16 | error: red, 17 | }, 18 | }, 19 | }, 20 | { 21 | id: 'custom', 22 | white: 'text-white', 23 | source: { 24 | bg: 'dark', 25 | bgColor: 'bg-dark', 26 | palette: { 27 | primary: white, 28 | secondary: white, 29 | error: red, 30 | }, 31 | }, 32 | }, 33 | ] 34 | 35 | export default themes 36 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import App from './App' 4 | 5 | render(, document.getElementById('root')) 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/pages/DialogDemo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useIntl } from 'react-intl' 3 | import Page from 'bootstrap-shell/lib/containers/Page/Page' 4 | 5 | 6 | const Dialog = () => { 7 | const intl = useIntl() 8 | 9 | return 13 | Dialog Demo 14 | 15 | } 16 | 17 | export default Dialog 18 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/pages/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Page from 'bootstrap-shell/lib/containers/Page/Page' 3 | 4 | export default function Home() { 5 | 6 | return ( 7 | Hallo 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/pages/LandingPage/LandingPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | const LandingPage = () => { 5 | return ( 6 |
19 |

Cool Landing Page

20 | 21 |
22 | Home 23 |
24 |
25 | ) 26 | } 27 | export default LandingPage 28 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/pages/LandingPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './LandingPage' 2 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/cra-template-bs/template/src/pages/PageNotFound/PageNotFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useIntl } from 'react-intl' 3 | 4 | const PageNotFound = () => { 5 | const intl = useIntl() 6 | 7 | return ( 8 |
9 | 404 10 |
11 | ) 12 | } 13 | 14 | export default PageNotFound 15 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import App from '../../cra-template-bs/template/src/App' 4 | 5 | render(, document.querySelector('#demo')) 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/nwb.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | type: 'react-component', 5 | npm: { 6 | esModules: true, 7 | umd: false, 8 | }, 9 | webpack: { 10 | extra: { 11 | devtool: 'inline-source-map', 12 | }, 13 | aliases: { 14 | 'bootstrap-shell/lib': path.resolve('src'), 15 | }, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/components/Menu/MenuDropdown.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import * as BS from "react-bootstrap" 3 | 4 | export default function MenuDropdown({ navItem, className }) { 5 | 6 | return ( 7 | navItem && 8 | 9 | {navItem?.nested?.map(item => { 10 | return item.nested ? 11 | : {item.displayName} 12 | 13 | })} 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/components/Menu/MenuDropdownMobile.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import * as BS from "react-bootstrap" 3 | import { BsChevronDown } from "react-icons/bs" 4 | 5 | export default function MenuDropdownMobile({ navItem, className }) { 6 | const [menuOpen, setMenuOpen] = useState(false); 7 | return ( 8 | 15 |
setMenuOpen(!menuOpen)} className="text-secondary">{navItem.displayName}
18 | {navItem.nested?.map(menuItem => { 19 | return menuItem.nested ? : 20 | 21 | {menuItem.displayName} 22 | 23 | })} 24 |
25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/components/Modal/index.js: -------------------------------------------------------------------------------- 1 | import { Modal } from 'react-bootstrap' 2 | 3 | import React from 'react' 4 | 5 | export default function index(props) { 6 | return ( 7 | 8 | 9 | 1 Title {' '} 10 | {' '} 11 | 12 |

here is the body

{' '} 13 |
{' '} 14 | 15 |

Issa footer

{' '} 16 |
{' '} 17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/containers/LayoutContainer/LayoutContainer.js: -------------------------------------------------------------------------------- 1 | import { useConfig } from 'base-shell/lib/providers/Config' 2 | import React from 'react' 3 | import MenuProvider from '../../providers/Menu/Provider' 4 | import '../../styles/custom-bootstrap.css'; 5 | 6 | const LayoutContent = ({ children }) => { 7 | return ( 8 |
14 | {children} 15 |
16 | ) 17 | } 18 | 19 | export default function ({ children }) { 20 | const { appConfig } = useConfig() 21 | return ( 22 | 23 | 24 | 25 | {children} 26 | 27 | 28 | 34 | 35 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/containers/Page/Page.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import Menu from '../../components/Menu/Menu' 3 | import { useMenu } from '../../providers/Menu' 4 | import * as BS from "react-bootstrap" 5 | 6 | const Page = ({ 7 | children, 8 | brand, 9 | contentStyle, 10 | }) => { 11 | let headerTitle = '' 12 | 13 | if (typeof brand === 'string' || brand instanceof String) { 14 | headerTitle = brand 15 | } 16 | 17 | return ( 18 | 19 | 20 |
21 | {children} 22 |
23 | 24 | ) 25 | } 26 | 27 | export default Page -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/index.js: -------------------------------------------------------------------------------- 1 | import config from './config' 2 | 3 | export default config 4 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/Context.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const Context = React.createContext(null) 4 | 5 | export default Context 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/Provider.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer } from 'react' 2 | import PropTypes from 'prop-types' 3 | import Context from './Context' 4 | import { 5 | setIsMobileMenuOpen 6 | } from './store/actions'; 7 | import reducer from './store/reducer'; 8 | import { SET_IS_MOBILE_MENU_OPEN } from './store/types'; 9 | 10 | const Provider = ({ appConfig, children, persistKey = 'menu' }) => { 11 | const { menu } = appConfig || {}; 12 | const { initialMobileMenuOpen } = menu; 13 | const savedState = JSON.parse(localStorage.getItem(persistKey)) 14 | const [menuStore, dispatch] = useReducer(reducer, { 15 | isMobileMenuOpen: initialMobileMenuOpen, 16 | ...savedState, 17 | }); 18 | 19 | const props = { 20 | DISPATCH_ACTION(value, newValue = null) { 21 | if (value === SET_IS_MOBILE_MENU_OPEN) { 22 | dispatch(setIsMobileMenuOpen(!menuStore.isMobileMenuOpen)); 23 | } 24 | }, 25 | 26 | // getters 27 | isMobileMenuOpen: menuStore.isMobileMenuOpen, 28 | } 29 | 30 | useEffect(() => { 31 | try { 32 | localStorage.setItem(persistKey, JSON.stringify(menuStore)) 33 | } catch (error) { 34 | console.warn(error) 35 | } 36 | }, [menuStore, persistKey]) 37 | 38 | return ( 39 | 42 | {children} 43 | 44 | ) 45 | } 46 | 47 | Provider.propTypes = { 48 | children: PropTypes.any, 49 | } 50 | 51 | export default Provider 52 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/index.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context from './Context' 3 | export { default as withMenu } from './with.js' 4 | export { default } from './Provider.js' 5 | 6 | export function useMenu() { 7 | return useContext(Context) 8 | } 9 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/store/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './types' 2 | 3 | export function setIsMobileMenuOpen(payload) { 4 | return { 5 | type: types.SET_IS_MOBILE_MENU_OPEN, 6 | payload: payload 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/store/reducer.js: -------------------------------------------------------------------------------- 1 | import * as types from './types' 2 | 3 | export default function reducer(state = {}, action) { 4 | const { type, payload } = action 5 | switch (type) { 6 | case types.SET_IS_MOBILE_MENU_OPEN: 7 | return { ...state, isMobileMenuOpen: payload } 8 | default: 9 | return state 10 | } 11 | } -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/store/types.js: -------------------------------------------------------------------------------- 1 | export const SET_IS_MOBILE_MENU_OPEN = 'SET_IS_MOBILE_MENU_OPEN'; 2 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Menu/with.js: -------------------------------------------------------------------------------- 1 | import Context from './Context' 2 | import React from 'react' 3 | 4 | const withContainer = (Component) => { 5 | const ChildComponent = (props) => { 6 | return ( 7 | 8 | {(contextProps) => { 9 | return 10 | }} 11 | 12 | ) 13 | } 14 | 15 | return ChildComponent 16 | } 17 | 18 | export default withContainer 19 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/Context.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const Context = React.createContext(null) 4 | 5 | export default Context 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/Provider.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useReducer } from 'react' 2 | import PropTypes from 'prop-types' 3 | import Context from './Context' 4 | import { 5 | setIsMobileMenuOpen 6 | } from './store/actions'; 7 | import reducer from './store/reducer'; 8 | import { SET_IS_MOBILE_MENU_OPEN } from './store/types'; 9 | 10 | const Provider = ({ appConfig, children, persistKey = 'menu' }) => { 11 | const { menu } = appConfig || {}; 12 | const { initialMobileMenuOpen } = menu; 13 | const savedState = JSON.parse(localStorage.getItem(persistKey)) 14 | const [menuStore, dispatch] = useReducer(reducer, { 15 | isMobileMenuOpen: initialMobileMenuOpen, 16 | ...savedState, 17 | }); 18 | 19 | const props = { 20 | DISPATCH_ACTION(value, newValue = null) { 21 | if (value === SET_IS_MOBILE_MENU_OPEN) { 22 | dispatch(setIsMobileMenuOpen(!menuStore.isMobileMenuOpen)); 23 | } 24 | }, 25 | 26 | // getters 27 | isMobileMenuOpen: menuStore.isMobileMenuOpen, 28 | } 29 | 30 | useEffect(() => { 31 | try { 32 | localStorage.setItem(persistKey, JSON.stringify(menuStore)) 33 | } catch (error) { 34 | console.warn(error) 35 | } 36 | }, [menuStore, persistKey]) 37 | 38 | return ( 39 | 42 | {children} 43 | 44 | ) 45 | } 46 | 47 | Provider.propTypes = { 48 | children: PropTypes.any, 49 | } 50 | 51 | export default Provider 52 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/index.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context from './Context' 3 | export { default as withMenu } from './with.js' 4 | export { default } from './Provider.js' 5 | 6 | export function useMenu() { 7 | return useContext(Context) 8 | } 9 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/store/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './types' 2 | 3 | export function setIsMobileMenuOpen(payload) { 4 | return { 5 | type: types.SET_IS_MOBILE_MENU_OPEN, 6 | payload: payload 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/store/reducer.js: -------------------------------------------------------------------------------- 1 | import * as types from './types' 2 | 3 | export default function reducer(state = {}, action) { 4 | const { type, payload } = action 5 | switch (type) { 6 | case types.SET_IS_MOBILE_MENU_OPEN: 7 | return { ...state, isMobileMenuOpen: payload } 8 | default: 9 | return state 10 | } 11 | } -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/store/types.js: -------------------------------------------------------------------------------- 1 | export const SET_IS_MOBILE_MENU_OPEN = 'SET_IS_MOBILE_MENU_OPEN'; 2 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Modal/with.js: -------------------------------------------------------------------------------- 1 | import Context from './Context' 2 | import React from 'react' 3 | 4 | const withContainer = (Component) => { 5 | const ChildComponent = (props) => { 6 | return ( 7 | 8 | {(contextProps) => { 9 | return 10 | }} 11 | 12 | ) 13 | } 14 | 15 | return ChildComponent 16 | } 17 | 18 | export default withContainer 19 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Theme/Context.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const Context = React.createContext(null) 4 | 5 | export default Context 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Theme/index.js: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context from './Context' 3 | export { default as withTheme } from './with.js' 4 | export { default } from './Provider.js' 5 | 6 | export function useTheme() { 7 | return useContext(Context) 8 | } 9 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/providers/Theme/with.js: -------------------------------------------------------------------------------- 1 | import Context from './Context' 2 | import React from 'react' 3 | 4 | const withContainer = (Component) => { 5 | const ChildComponent = (props) => { 6 | return ( 7 | 8 | {(contextProps) => { 9 | return 10 | }} 11 | 12 | ) 13 | } 14 | 15 | return ChildComponent 16 | } 17 | 18 | export default withContainer 19 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/styles/custom-bootstrap.css: -------------------------------------------------------------------------------- 1 | /* 2 | xs = Extra small <576px. Max container width None (auto) 3 | sm = Small ≥576px. Max container width 540px. 4 | md = Medium ≥768px. Max container width 720px. 5 | lg = Large ≥992px. Max container width 960px. 6 | xl = Extra large ≥1200px. Max container width 1140px. 7 | */ 8 | 9 | :root { 10 | --bs-primary: white !important; 11 | --bs-primary-rgb: 52, 58, 64 !important; 12 | } 13 | 14 | .dropdown-menu { 15 | min-width: 12rem !important; 16 | } 17 | 18 | .dropdown-submenu { 19 | position: relative; 20 | } 21 | 22 | .dropdown-submenu .dropdown-menu[data-bs-popper] { 23 | right: 0; 24 | top: -3px; 25 | left: 99%; 26 | } 27 | 28 | .dropdown-toggle { 29 | padding: 0.25rem 1rem !important; 30 | } 31 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/src/utils/theme.js: -------------------------------------------------------------------------------- 1 | //import { createTheme } from '@mui/material/styles' 2 | import { createTheme } from '@mui/material/styles' 3 | 4 | const getThemeSource = (id, ts, isDarkMode, isRTL) => { 5 | if (ts) { 6 | for (let i = 0; i < ts.length; i++) { 7 | if (ts[i]['id'] === id) { 8 | const source = ts[i]['source'] 9 | const palette = source != null ? source.palette : {} 10 | return createTheme({ 11 | ...source, 12 | palette: { ...palette, mode: isDarkMode ? 'dark' : 'light' }, 13 | direction: isRTL ? 'rtl' : 'ltr', 14 | }) 15 | } 16 | } 17 | } 18 | 19 | return createTheme({ 20 | palette: { mode: isDarkMode ? 'dark' : 'light' }, 21 | direction: isRTL ? 'rtl' : 'ltr', 22 | }) 23 | } 24 | 25 | export default getThemeSource 26 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/bootstrap-shell/tests/index.test.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | import React from 'react' 3 | import {render, unmountComponentAtNode} from 'react-dom' 4 | 5 | import Component from 'src/' 6 | 7 | describe('Component', () => { 8 | let node 9 | 10 | beforeEach(() => { 11 | node = document.createElement('div') 12 | }) 13 | 14 | afterEach(() => { 15 | unmountComponentAtNode(node) 16 | }) 17 | 18 | it('displays a welcome message', () => { 19 | render(, node, () => { 20 | expect(node.innerHTML).toContain('Welcome to React components') 21 | }) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | /es 4 | /lib 5 | /node_modules 6 | /umd 7 | npm-debug.log* 8 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 8 6 | 7 | before_install: 8 | - npm install codecov.io coveralls 9 | 10 | after_success: 11 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 12 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 13 | 14 | branches: 15 | only: 16 | - master 17 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/README.md: -------------------------------------------------------------------------------- 1 | # firebase-function-tools 2 | 3 | Based on this [article](https://codeburst.io/organizing-your-firebase-cloud-functions-67dc17b3b0da) 4 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/nwb.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | type: 'react-component', 3 | npm: { 4 | esModules: false, 5 | umd: false, 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/src/counting.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | handleListChange: (data, context, counterName) => { 3 | if (data.after.exists() && data.before.exists()) { 4 | return null 5 | } 6 | 7 | const collectionRef = data.after.ref.parent 8 | const countRef = collectionRef.parent.child(counterName) 9 | 10 | // Return the promise from countRef.transaction() so our function 11 | // waits for this async event to complete before it exits. 12 | return countRef.transaction(current => { 13 | if (data.after.exists()) { 14 | return (current || 0) + 1 15 | } else { 16 | return (current || 0) - 1 17 | } 18 | }) 19 | }, 20 | handleRecount: (data, context, listName, correction = 0) => { 21 | if (!data.exists()) { 22 | const counterRef = data.ref 23 | const collectionRef = counterRef.parent.child(listName) 24 | 25 | // Return the promise from counterRef.set() so our function 26 | // waits for this async event to complete before it exits. 27 | return collectionRef 28 | .once('value') 29 | .then(messagesData => 30 | counterRef.set(messagesData.numChildren() + correction) 31 | ) 32 | } 33 | return null 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/src/customClaims.js: -------------------------------------------------------------------------------- 1 | import admin from 'firebase-admin' 2 | 3 | const setClaim = async (uid, name, value = true) => { 4 | const user = await admin.auth().getUser(uid) 5 | 6 | const { [name]: claimName, ...rest } = user.customClaims || {} 7 | 8 | await admin.auth().setCustomUserClaims(uid, { ...rest, [name]: value }) 9 | } 10 | 11 | const removeClaim = async (uid, name) => { 12 | const user = await admin.auth().getUser(uid) 13 | 14 | const { [name]: claimName, ...rest } = user.customClaims || {} 15 | 16 | await admin.auth().setCustomUserClaims(uid, { ...rest }) 17 | } 18 | 19 | export { setClaim, removeClaim } 20 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/src/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './load' 2 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/src/notifications.js: -------------------------------------------------------------------------------- 1 | const admin = require('firebase-admin') 2 | 3 | module.exports = { 4 | notifyUser: (userUid, payload, tokensBasePath = 'notification_tokens') => { 5 | console.log(userUid, payload) 6 | 7 | return admin 8 | .database() 9 | .ref(`/${tokensBasePath}/${userUid}`) 10 | .once('value') 11 | .then(snapshot => { 12 | let registrationTokens = [] 13 | 14 | snapshot.forEach(token => { 15 | if (token.val()) { 16 | registrationTokens.push(token.key) 17 | } 18 | }) 19 | 20 | if (registrationTokens.length) { 21 | return admin.messaging().sendToDevice(registrationTokens, payload) 22 | } else { 23 | console.log('Not tokens registered') 24 | return null 25 | } 26 | }) 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/src/users.js: -------------------------------------------------------------------------------- 1 | const admin = require('firebase-admin') 2 | 3 | // Source: https://firebase.google.com/docs/auth/admin/manage-users 4 | const listAllUsers = (userIds = [], nextPageToken) => { 5 | // List batch of users, 1000 at a time. 6 | return admin 7 | .auth() 8 | .listUsers(1000, nextPageToken) 9 | .then(resp => { 10 | if (resp.pageToken) { 11 | // List next batch of users. 12 | return listAllUsers(userIds.concat(resp.users), resp.pageToken) 13 | } 14 | return userIds.concat(resp.users) 15 | }) 16 | } 17 | 18 | module.exports = { 19 | listAllUsers: listAllUsers, 20 | } 21 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/firebase-function-tools/tests/index-test.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | import React from 'react' 3 | import {render, unmountComponentAtNode} from 'react-dom' 4 | 5 | import Component from 'src/' 6 | 7 | describe('Component', () => { 8 | let node 9 | 10 | beforeEach(() => { 11 | node = document.createElement('div') 12 | }) 13 | 14 | afterEach(() => { 15 | unmountComponentAtNode(node) 16 | }) 17 | 18 | it('displays a welcome message', () => { 19 | render(, node, () => { 20 | expect(node.innerHTML).toContain('Welcome to React components') 21 | }) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /packages/material-ui-shell/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /dist 3 | /node_modules 4 | npm-debug.log* 5 | stats.html 6 | -------------------------------------------------------------------------------- /packages/material-ui-shell/README.md: -------------------------------------------------------------------------------- 1 | # material-ui-shell 2 | 3 | [![Travis][build-badge]][build] 4 | [![npm package][npm-badge]][npm] 5 | [![Coveralls][coveralls-badge]][coveralls] 6 | 7 | Describe material-ui-shell here. 8 | 9 | [build-badge]: https://img.shields.io/travis/user/repo/master.png?style=flat-square 10 | [build]: https://travis-ci.org/user/repo 11 | 12 | [npm-badge]: https://img.shields.io/npm/v/npm-package.png?style=flat-square 13 | [npm]: https://www.npmjs.org/package/npm-package 14 | 15 | [coveralls-badge]: https://img.shields.io/coveralls/user/repo/master.png?style=flat-square 16 | [coveralls]: https://coveralls.io/github/user/repo 17 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ecronix/create-material-ui-shell", 3 | "version": "1.0.38", 4 | "description": "A template to create new projects based on @ecronix/material-ui-shell", 5 | "bin": { 6 | "create-my-template": "index.js" 7 | }, 8 | "main": "index.js", 9 | "devDependencies": { 10 | "material-ui-shell-template": "^1.0.41" 11 | }, 12 | "scripts": { 13 | "start": "node index.js" 14 | }, 15 | "keywords": [ 16 | "ecronix", 17 | "material-ui-shell", 18 | "react-most-wanted" 19 | ], 20 | "author": "Abdallah", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/.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 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | firebase-debug.log* 26 | dist 27 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | }, 5 | "include": ["src"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-ui-shell-template", 3 | "version": "1.0.41", 4 | "description": "This project was bootstrapped with [@ecronix/material-ui](https://github.com/ecronix/react-most-wanted)", 5 | "type": "module", 6 | "private": "true", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "serve": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@ecronix/material-ui-shell": "^3.5.54" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^4", 17 | "vite": "^5" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "ISC" 22 | } 23 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/material-ui-shell/create-material-ui-shell/template/public/favicon.ico -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/material-ui-shell/create-material-ui-shell/template/public/logo192.png -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/material-ui-shell/create-material-ui-shell/template/public/logo512.png -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Ecronix - React App", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 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 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/components/CustomPaper/index.jsx: -------------------------------------------------------------------------------- 1 | import Paper from '@mui/material/Paper' 2 | import { styled } from '@mui/material' 3 | 4 | const CustomPaper = styled(Paper)(({ theme }) => { 5 | return { 6 | width: 'auto', 7 | marginLeft: theme.spacing(8), 8 | marginRight: theme.spacing(8), 9 | [theme.breakpoints.up(620)]: { 10 | width: 400, 11 | marginLeft: 'auto', 12 | marginRight: 'auto', 13 | }, 14 | marginTop: theme.spacing(8), 15 | display: 'flex', 16 | flexDirection: 'column', 17 | alignItems: 'center', 18 | padding: `18px 18px 18px`, 19 | } 20 | }) 21 | 22 | export default CustomPaper 23 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/config/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './config' 2 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/config/locales/index.js: -------------------------------------------------------------------------------- 1 | const locales = [ 2 | { 3 | locale: 'en', 4 | messages: import('./en'), 5 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/en`), 6 | }, 7 | { 8 | locale: 'ru', 9 | messages: import('./ru'), 10 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/ru`), 11 | }, 12 | { 13 | locale: 'de', 14 | messages: import('./de'), 15 | //loadData: import(`@formatjs/intl-relativetimeformat/dist/locale-data/de`), 16 | }, 17 | ] 18 | 19 | export default locales 20 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/config/themes.js: -------------------------------------------------------------------------------- 1 | import red from '@mui/material/colors/red' 2 | import green from '@mui/material/colors/green' 3 | import pink from '@mui/material/colors/pink' 4 | 5 | const themes = [ 6 | { 7 | id: 'default', 8 | }, 9 | { 10 | id: 'red', 11 | color: red[500], 12 | source: { 13 | palette: { 14 | primary: red, 15 | secondary: pink, 16 | error: red, 17 | }, 18 | }, 19 | }, 20 | { 21 | id: 'green', 22 | color: green[500], 23 | source: { 24 | palette: { 25 | primary: green, 26 | secondary: red, 27 | error: red, 28 | }, 29 | }, 30 | }, 31 | ] 32 | 33 | export default themes 34 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/demo-index.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import { AppContainer } from '@ecronix/base-shell' 4 | import config from './config' 5 | 6 | createRoot(document.getElementById('root')).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/About/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { useIntl } from 'react-intl' 3 | import { Page, Scrollbar } from '@ecronix/material-ui-shell' 4 | import ReactMarkdown from 'react-markdown' 5 | 6 | export const AboutPage = () => { 7 | const [source, setSource] = useState(null) 8 | const intl = useIntl() 9 | 10 | const loadData = async () => { 11 | const data = await fetch( 12 | 'https://raw.githubusercontent.com/TarikHuber/react-most-wanted/master/README.md' 13 | ) 14 | const text = await data.text() 15 | setSource(text) 16 | } 17 | 18 | useEffect(() => { 19 | loadData() 20 | }, []) 21 | 22 | return ( 23 | 26 | 27 |
28 | {source && ( 29 | 30 | )} 31 |
32 |
33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import { Typography } from '@mui/material' 2 | import { Page } from '@ecronix/material-ui-shell' 3 | import React from 'react' 4 | import { useIntl } from 'react-intl' 5 | 6 | export const HomePage = () => { 7 | const intl = useIntl() 8 | 9 | return ( 10 | 11 | {intl.formatMessage({ id: 'home' })} 12 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/LandingPage/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | export const LandingPage = () => { 5 | return ( 6 |
19 |

Cool Landing Page

20 | 21 |
22 | Home 23 |
24 |
25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/PageNotFound/index.jsx: -------------------------------------------------------------------------------- 1 | import { Button, Paper, Typography } from '@mui/material' 2 | import { Home } from '@mui/icons-material' 3 | import { Page } from '@ecronix/material-ui-shell' 4 | import React from 'react' 5 | import { useIntl } from 'react-intl' 6 | 7 | export const PageNotFound = () => { 8 | const intl = useIntl() 9 | 10 | return ( 11 | 12 | t.palette.background.default, 15 | margin: 0, 16 | height: `calc(100vh - 64px)`, 17 | }} 18 | > 19 |
28 | 404 29 | 30 | {intl.formatMessage({ id: 'page_not_found' }) + ' MUI'} 31 | 32 | 40 |
41 |
42 |
43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/TabsDemo/index.jsx: -------------------------------------------------------------------------------- 1 | import { AppBar, Tab, Tabs } from '@mui/material' 2 | import { Page } from '@ecronix/material-ui-shell' 3 | import React, { useState } from 'react' 4 | import { useIntl } from 'react-intl' 5 | 6 | export const TabsDemoPage = () => { 7 | const [tab, setTab] = useState('one') 8 | const intl = useIntl() 9 | 10 | return ( 11 | 18 | setTab(t)} 21 | aria-label="simple tabs example" 22 | centered 23 | textColor="inherit" 24 | indicatorColor="secondary" 25 | > 26 | 27 | 28 | 29 | 30 | 31 | } 32 | > 33 |
34 | {tab === 'one' &&
One
} 35 | {tab === 'two' &&
Two
} 36 | {tab === 'three' &&
Three
} 37 |
38 |
39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/src/pages/ToastDemo/index.jsx: -------------------------------------------------------------------------------- 1 | import { Button } from '@mui/material' 2 | import { Page } from '@ecronix/material-ui-shell' 3 | import React from 'react' 4 | import { useIntl } from 'react-intl' 5 | import { useSnackbar } from 'notistack' 6 | 7 | export const ToastDemoPage = () => { 8 | const intl = useIntl() 9 | const { enqueueSnackbar } = useSnackbar() 10 | 11 | return ( 12 | 18 |
19 | 32 |
33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /packages/material-ui-shell/create-material-ui-shell/template/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | setupNodeEvents(on, config) { 6 | // implement node event listeners here 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress/e2e/spec.cy.js: -------------------------------------------------------------------------------- 1 | describe('My React App', () => { 2 | beforeEach(() => { 3 | cy.visit('http://localhost:5173') 4 | }) 5 | 6 | it('renders the app', () => { 7 | cy.get('#root').should('exist') 8 | }) 9 | 10 | it('renders "app container top" text', () => { 11 | cy.contains('Cool Landing Page').should('exist') 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress/screenshots/spec.cy.js/My React App -- renders app container top text (failed).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/material-ui-shell/cypress/screenshots/spec.cy.js/My React App -- renders app container top text (failed).png -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -------------------------------------------------------------------------------- /packages/material-ui-shell/cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') -------------------------------------------------------------------------------- /packages/material-ui-shell/demo.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './cra-template-material-ui/template/src/App' 4 | 5 | createRoot(document.getElementById('root')).render( 6 | 7 | 8 | 9 | ) 10 | -------------------------------------------------------------------------------- /packages/material-ui-shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/components/Loading/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import CircularProgress from '@mui/material/CircularProgress' 3 | 4 | /** 5 | * @description Circular loading indicator. 6 | * @returns CircularProgress component with size of 50 7 | */ 8 | export default function Loading(): JSX.Element { 9 | return ( 10 |
22 | 23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/components/index.ts: -------------------------------------------------------------------------------- 1 | // there are both named and default exports under /components, 2 | // default are used mainly when lazy loading is needed 3 | // named are used when we need to import multiple components conveniently 4 | 5 | export { default as FilterDrawer } from './FilterDrawer' 6 | export { default as Scrollbar } from './Scrollbar' 7 | export { default as MenuHeader } from './MenuHeader' 8 | export { default as QuestionDialog } from './QuestionDialog' 9 | export { default as SearchField } from './SearchField' 10 | export { default as Loading } from './Loading' 11 | export { default as UpdateDialog } from './UpdateDialog' 12 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/containers/Menu/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ResponsiveMenuContainer } from '@ecronix/material-ui-shell' 3 | import { useConfig } from '@ecronix/base-shell' 4 | 5 | /** 6 | * React component rendering MenuHeader and MenuContent. It loads data from config using useConfig hook. 7 | * It renders MenuHeader and MenuContent component if they are provided in application configuration under 8 | * menu scetion. As main wrapper it sets BaseMenu component defined in app config under menu section 9 | * 10 | * If MenuContainer is not provided it uses ResponsiveMenuContainer from material-ui-shell 11 | * 12 | * @example 13 | * appConfig: { 14 | * components: { 15 | * Menu: MenuContainer 16 | * } 17 | * } 18 | * @see {ResponsiveMenuContainer} - for fallback component 19 | */ 20 | export function MenuContainer() { 21 | const { appConfig } = useConfig() 22 | const { menu } = appConfig || {} 23 | const { MenuHeader, MenuContent, BaseMenu } = menu || {} 24 | 25 | const Menu = BaseMenu || ResponsiveMenuContainer 26 | 27 | return ( 28 | 29 | {MenuHeader && } 30 | {MenuContent && } 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/containers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ImageUploadDialog' 2 | export * from './LayoutContainer' 3 | export * from './Menu' 4 | export * from './ResponsiveMenu' 5 | export * from './SelectableMenuList' 6 | export * from './UpdateContainer' 7 | export * from './VirtualList' 8 | export type { IPixelCrop } from './ImageUploadDialog/getCropImage' 9 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components' 2 | export * from './containers' 3 | export * from './providers' 4 | export * from './utils' 5 | export * from './pages' 6 | export * from './common.type' 7 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/pages/LandingPage/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export function LandingPage() { 4 | return
Landing Page MUI
5 | } 6 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/pages/PageNotFound/index.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Paper, Typography } from '@mui/material' 2 | import { Home } from '@mui/icons-material' 3 | import { Page } from '@ecronix/material-ui-shell' 4 | import React from 'react' 5 | import { useIntl } from 'react-intl' 6 | 7 | /** 8 | * @description Renders not found page 9 | */ 10 | export const NotFoundPage: React.FC = () => { 11 | const intl = useIntl() 12 | 13 | return ( 14 | 15 | t.palette.background.default, 18 | margin: 0, 19 | height: `calc(100vh - 64px)`, 20 | }} 21 | > 22 |
31 | 404 32 | 33 | {intl.formatMessage({ id: 'page_not_found' }) + ' MUI'} 34 | 35 | 43 |
44 |
45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/pages/index.ts: -------------------------------------------------------------------------------- 1 | export { Page } from './Page' 2 | export { NotFoundPage } from './PageNotFound' 3 | export { ListPage } from './ListPage' 4 | export { LandingPage } from './LandingPage' 5 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Dialogs/Question/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export interface DialogsContextType { 4 | /** 5 | * @description Open dialog - sets isOpen to true, and pass additional props 6 | * @param props 7 | */ 8 | openDialog: (props: any) => void 9 | 10 | /** 11 | * @description Closes dialog - sets isOpen to false 12 | * @param name 13 | * @param offset 14 | */ 15 | closeDialog: () => void 16 | /** 17 | * @description Set processing to true or false 18 | * @param isProcessing 19 | */ 20 | setProcessing: (isProcessing: boolean) => void 21 | } 22 | 23 | export const Context = React.createContext( 24 | undefined 25 | ) 26 | 27 | export default Context 28 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Dialogs/Question/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, Fragment } from 'react' 2 | import Context from './Context' 3 | import QuestionDialog from '../../../components/QuestionDialog' 4 | import { IProviderProps } from '@ecronix/material-ui-shell/common.type' 5 | 6 | const Provider: React.FC = ({ children }) => { 7 | const [state, setState] = useState({ isOpen: false }) 8 | const [isProcessing, setIsProcessing] = useState(false) 9 | 10 | const openDialog = (props: any) => { 11 | setState({ isOpen: true, ...props }) 12 | } 13 | 14 | const closeDialog = () => { 15 | setState({ isOpen: false }) 16 | } 17 | 18 | const setProcessing = (isProcessing: boolean) => { 19 | setIsProcessing(isProcessing) 20 | } 21 | 22 | return ( 23 | 24 | 25 | {children} 26 | 31 | 32 | 33 | ) 34 | } 35 | 36 | export default Provider 37 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Dialogs/Question/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context, { DialogsContextType } from './Context' 3 | import Provider from './Provider' 4 | 5 | /** 6 | * Custom hook to access the question dialog context. 7 | * 8 | * @function 9 | * @returns {DialogsContextType} The theme context value. 10 | * @throws {Error} If used outside of an QuestionsDialogProvider. 11 | * @example 12 | * const { openDialog, closeDialog, setProcessing } = useQuestionsDialog(); 13 | * 14 | * @description Gives you access to questions dialog. It must be used within QuestionsDialogProvider and it provides you 15 | * with methods for opening and closing dialog, as well as handling processing 16 | * 17 | */ 18 | function useQuestionsDialog(): DialogsContextType { 19 | const context = useContext(Context) 20 | if (context === undefined) { 21 | throw new Error( 22 | 'useQuestionsDialog must be used within a QuestionsDialogProvider' 23 | ) 24 | } 25 | return context 26 | } 27 | 28 | export { 29 | useQuestionsDialog, 30 | Context as QuestionsDialogContext, 31 | Provider as QuestionsDialogProvider, 32 | } 33 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Filter/fields/index.ts: -------------------------------------------------------------------------------- 1 | import numberField from './number' 2 | import textField from './text' 3 | import boolField from './boolean' 4 | import dateField from './date' 5 | import timeField from './time' 6 | 7 | export { numberField, textField, boolField, dateField, timeField } 8 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Filter/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context from './Context' 3 | import Provider from './Provider' 4 | 5 | function useFilter() { 6 | const context = useContext(Context) 7 | 8 | if (context === undefined) { 9 | throw new Error('useFilter must be used within a FilterProvider') 10 | } 11 | return context 12 | } 13 | 14 | export { useFilter, Context as FilterContext, Provider as FilterProvider } 15 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Filter/store/types.tsx: -------------------------------------------------------------------------------- 1 | export const ON_FILTER_IS_OPEN = 'filters@ON_FILTER_IS_OPEN' 2 | export const ON_FILTER_IS_CLOSE = 'filters@ON_FILTER_IS_CLOSE' 3 | export const ON_FILTER_SORT_FIELD_CHANGED = 4 | 'filters@ON_FILTER_SORT_FIELD_CHANGED' 5 | export const ON_FILTER_SORT_ORIENTATION_CHANGED = 6 | 'filters@ON_FILTER_SORT_ORIENTATION_CHANGED' 7 | export const ON_ADD_FILTER_QUERY = 'filters@ON_ADD_FILTER_QUERY' 8 | export const ON_EDIT_FILTER_QUERY = 'filters@ON_EDIT_FILTER_QUERY' 9 | export const ON_REMOVE_FILTER_QUERY = 'filters@ON_REMOVE_FILTER_QUERY' 10 | export const ON_SET_SEARCH = 'filters@ON_SET_SEARCH' 11 | export const ON_CLEAR = 'filters@ON_CLEAR' 12 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Menu/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export enum togglerTypes { 4 | isAuthMenuOpen = 'isAuthMenuOpen', 5 | isMiniMode = 'isMiniMode', 6 | isMenuOpen = 'isMenuOpen', 7 | isMobileMenuOpen = 'isMobileMenuOpen', 8 | isMiniSwitchVisibility = 'isMiniSwitchVisibility', 9 | } 10 | 11 | export type MenuContextType = { 12 | /** Method for updating context values. Use `togglerTypes` enum to access properties. Provide new value to set to specified property */ 13 | toggleThis: (value: togglerTypes, newValue?: boolean | null) => void 14 | isDesktop: boolean 15 | isAuthMenuOpen?: boolean 16 | isMiniMode?: boolean 17 | isMenuOpen?: boolean 18 | isMobileMenuOpen?: boolean 19 | isMiniSwitchVisibility?: boolean 20 | } 21 | 22 | export const Context = React.createContext( 23 | undefined 24 | ) 25 | 26 | export default Context 27 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Menu/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context, { MenuContextType } from './Context' 3 | import Provider from './Provider' 4 | 5 | /** 6 | * Custom hook to access the menu context. 7 | * 8 | * @function 9 | * @returns {MenuContextType} The menu context value. 10 | * @throws {Error} If used outside of an MenuProvider. 11 | * @example 12 | * const menuContext = useMenu() 13 | * 14 | * @description Gives you access to menu context. Provides you with set of properties and method to update those 15 | * properties. Possible to change properties defined in `togglerTypes` enum. 16 | * Provides you with properties: 17 | * - isDesktop: boolean 18 | * - isAuthMenuOpen?: boolean 19 | * - isMiniMode?: boolean 20 | * - isMenuOpen?: boolean 21 | * - isMobileMenuOpen?: boolean 22 | * - isMiniSwitchVisibility?: boolean 23 | * 24 | * @see {togglerTypes} to check possible values to change with method 25 | */ 26 | function useMenu(): MenuContextType { 27 | const context = useContext(Context) 28 | 29 | if (context === undefined) { 30 | throw new Error('useMenu must be used within a MenuProvider') 31 | } 32 | return context 33 | } 34 | 35 | export { useMenu, Context as MenuContext, Provider as MenuProvider } 36 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Menu/store/reducer.tsx: -------------------------------------------------------------------------------- 1 | import { MenuContextType } from '../Context' 2 | import * as types from './types' 3 | 4 | type ReducerAction = { 5 | type: string 6 | payload: boolean 7 | } 8 | 9 | export default function reducer( 10 | state: Partial = {}, 11 | action: ReducerAction 12 | ) { 13 | const { type, payload } = action 14 | switch (type) { 15 | case types.SET_IS_AUTH_MENU_OPEN: 16 | return { ...state, isAuthMenuOpen: payload } 17 | case types.SET_IS_MINI_MODE: 18 | return { ...state, isMiniMode: payload } 19 | case types.SET_IS_MENU_OPEN: 20 | return { ...state, isMenuOpen: payload } 21 | case types.SET_IS_MOBILE_MENU_OPEN: 22 | return { ...state, isMobileMenuOpen: payload } 23 | case types.SET_IS_MINI_SWITCH_VISIBILITY: 24 | return { ...state, isMiniSwitchVisibility: payload } 25 | default: 26 | return state 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Menu/store/types.tsx: -------------------------------------------------------------------------------- 1 | export const SET_IS_AUTH_MENU_OPEN = 'SET_IS_AUTH_MENU_OPEN' 2 | export const SET_IS_MINI_MODE = 'SET_IS_MINI_MODE' 3 | export const SET_IS_MENU_OPEN = 'SET_IS_MENU_OPEN' 4 | export const SET_IS_MOBILE_MENU_OPEN = 'SET_IS_MOBILE_MENU_OPEN' 5 | export const SET_IS_MINI_SWITCH_VISIBILITY = 'SET_IS_MINI_SWITCH_VISIBILITY' 6 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Theme/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export interface ThemeContextType { 4 | /** 5 | * @description Changing theme id 6 | * @param auth 7 | */ 8 | setThemeID: (val: string) => void 9 | /** 10 | * @description Toggle dark mode ro RTL in this theme 11 | * @param mode - Parameter mode can be 'isRTL' or 'isDarkMode' and accordingly theme parameters will switch for that param 12 | */ 13 | toggleThisTheme: (mode: 'isRTL' | 'isDarkMode') => void 14 | 15 | /** 16 | * @description Boolean value definig if dark mode is enabled 17 | */ 18 | isDarkMode: boolean 19 | 20 | /** 21 | * @description Boolean value definig if RTL is enabled 22 | */ 23 | isRTL: boolean 24 | 25 | /** 26 | * @description Id of theme 27 | */ 28 | themeID: string 29 | } 30 | 31 | export const Context = React.createContext( 32 | undefined 33 | ) 34 | 35 | export default Context 36 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/Theme/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context, { ThemeContextType } from './Context' 3 | import Provider from './Provider' 4 | 5 | /** 6 | * Custom hook to access the theme context. 7 | * 8 | * @function 9 | * @returns {ThemeContextType} The theme context value. 10 | * @throws {Error} If used outside of an ThemeProvider. 11 | * @example 12 | * const theme = useTheme() 13 | * 14 | * @description Gives you access to theme context. Theme context provides you with set of methods and properties that define 15 | * look of the App. 16 | * Default values are provided in application configuration file. 17 | */ 18 | function useTheme(): ThemeContextType { 19 | const context = useContext(Context) 20 | 21 | if (context === undefined) { 22 | throw new Error('useTheme must be used within a ThemeProvider') 23 | } 24 | return context 25 | } 26 | 27 | export { useTheme, Context as ThemeContext, Provider as ThemeProvider } 28 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/VirtualLists/Context.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export interface VirtualListsContextType { 4 | /** 5 | * @description Set offset for provided name to provided value 6 | * @param name 7 | * @param offset 8 | */ 9 | setOffset: (name: string, offset: any) => void 10 | /** 11 | * @description Toggle dark mode ro RTL in this theme 12 | * @param name - Get offset by name 13 | */ 14 | getOffset: (name: string) => void 15 | } 16 | 17 | export const Context = React.createContext( 18 | undefined 19 | ) 20 | 21 | export default Context 22 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/VirtualLists/Provider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from 'react' 2 | import Context from './Context' 3 | import { IProviderProps } from '@ecronix/material-ui-shell/common.type' 4 | 5 | type ReducerAction = { 6 | type: string 7 | name: string 8 | offset: any 9 | } 10 | 11 | function reducer(state: any, action: ReducerAction) { 12 | const { type, name, offset } = action 13 | switch (type) { 14 | case 'SET_OFFSET': 15 | return { ...state, [name]: offset } 16 | default: 17 | throw new Error() 18 | } 19 | } 20 | 21 | const Provider: React.FC = ({ children }) => { 22 | const [state, dispatch] = useReducer(reducer, {}) 23 | 24 | const setOffset = (name: string, offset: any) => { 25 | dispatch({ type: 'SET_OFFSET', name, offset }) 26 | } 27 | 28 | const getOffset = (name: string) => { 29 | return state[name] || 0 30 | } 31 | 32 | return ( 33 | 34 | {children} 35 | 36 | ) 37 | } 38 | 39 | export default Provider 40 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/VirtualLists/index.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Context, { VirtualListsContextType } from './Context' 3 | import Provider from './Provider' 4 | 5 | /** 6 | * Custom hook to access virtual lists. 7 | * 8 | * @function 9 | * @returns {VirtualListsContextType} Virtual list context value. 10 | * @throws {Error} If used outside of an VirtualListsProvider. 11 | * @example 12 | * const { getOffset, setOffset } = useVirtualLists() 13 | * 14 | * @description 15 | * This hook provides access to the virtual lists context. It must be used withgin VirutalListsProvider. 16 | * It provides methods for setting and getting offset by name: 17 | * - setOffset 18 | * - getOffset 19 | * 20 | * @see {VirtualListsContextType} for methods reference 21 | */ 22 | function useVirtualLists(): VirtualListsContextType { 23 | const context = useContext(Context) 24 | 25 | if (context === undefined) { 26 | throw new Error( 27 | 'useVirtualLists must be used within a VirtualListsProvider' 28 | ) 29 | } 30 | return context 31 | } 32 | 33 | export { 34 | useVirtualLists, 35 | Context as VirtualListsContext, 36 | Provider as VirtualListsProvider, 37 | } 38 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './VirtualLists' 2 | export * from './Theme' 3 | export * from './Menu' 4 | export * from './Dialogs/Question' 5 | export * from './Filter' 6 | export { togglerTypes } from './Menu/Context' 7 | -------------------------------------------------------------------------------- /packages/material-ui-shell/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { createTheme } from '@mui/material/styles' 2 | import { ThemeType } from '../common.type' 3 | 4 | export const getThemeSource = ( 5 | id: string, 6 | ts: ThemeType[], 7 | isDarkMode: boolean, 8 | isRTL: boolean 9 | ) => { 10 | if (ts) { 11 | for (let i = 0; i < ts.length; i++) { 12 | if (ts[i]['id'] === id) { 13 | const source = ts[i]['source'] 14 | const palette = source != null ? source.palette : {} 15 | return createTheme({ 16 | ...source, 17 | palette: { ...palette, mode: isDarkMode ? 'dark' : 'light' }, 18 | direction: isRTL ? 'rtl' : 'ltr', 19 | }) 20 | } 21 | } 22 | } 23 | 24 | return createTheme({ 25 | palette: { mode: isDarkMode ? 'dark' : 'light' }, 26 | direction: isRTL ? 'rtl' : 'ltr', 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /packages/material-ui-shell/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../base-tsconfig.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@ecronix/material-ui-shell": ["./src"], 6 | "@ecronix/material-ui-shell/*": ["./src/*"] 7 | }, 8 | "declarationDir": "./dist/types" 9 | }, 10 | "include": ["src/**/*"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /packages/material-ui-shell/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | import path from 'path' 4 | import { visualizer } from 'rollup-plugin-visualizer' 5 | import { externalizeDeps } from 'vite-plugin-externalize-deps' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [react(), visualizer(), externalizeDeps()], 10 | resolve: { 11 | alias: { 12 | '@ecronix/material-ui-shell': path.resolve(__dirname, 'src'), 13 | }, 14 | extensions: ['.js', '.ts', '.jsx', '.tsx'], 15 | }, 16 | build: { 17 | minify: false, 18 | lib: { 19 | entry: path.resolve(__dirname, 'src/index.ts'), 20 | name: 'material-ui-shell', 21 | formats: ['es'], 22 | }, 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /packages/rmw-shell/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /dist 3 | /node_modules 4 | /umd 5 | npm-debug.log* 6 | stats.html 7 | -------------------------------------------------------------------------------- /packages/rmw-shell/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= 10 must be installed. 4 | 5 | ## Installation 6 | 7 | - Running `npm install` in the component's root directory will install everything you need for development. 8 | 9 | ## Demo Development Server 10 | 11 | - `npm start` will run a development server with the component's demo app at [http://localhost:3000](http://localhost:3000) with hot module reloading. 12 | 13 | ## Running Tests 14 | 15 | - `npm test` will run the tests once. 16 | 17 | - `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`. 18 | 19 | - `npm run test:watch` will run the tests on every change. 20 | 21 | ## Building 22 | 23 | - `npm run build` will build the component for publishing to npm and also bundle the demo app. 24 | 25 | - `npm run clean` will delete built resources. 26 | -------------------------------------------------------------------------------- /packages/rmw-shell/README.md: -------------------------------------------------------------------------------- 1 | # my-component 2 | 3 | [![Travis][build-badge]][build] 4 | [![npm package][npm-badge]][npm] 5 | [![Coveralls][coveralls-badge]][coveralls] 6 | 7 | Describe my-component here. 8 | 9 | [build-badge]: https://img.shields.io/travis/user/repo/master.png?style=flat-square 10 | [build]: https://travis-ci.org/user/repo 11 | 12 | [npm-badge]: https://img.shields.io/npm/v/npm-package.png?style=flat-square 13 | [npm]: https://www.npmjs.org/package/npm-package 14 | 15 | [coveralls-badge]: https://img.shields.io/coveralls/user/repo/master.png?style=flat-square 16 | [coveralls]: https://coveralls.io/github/user/repo 17 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ecronix/create-rmw-shell", 3 | "version": "1.0.40", 4 | "description": "A template to create new projects based on @ecronix/rmw-shell", 5 | "bin": { 6 | "create-my-template": "index.js" 7 | }, 8 | "main": "index.js", 9 | "devDependencies": { 10 | "rmw-shell-template": "^1.0.43" 11 | }, 12 | "scripts": { 13 | "start": "node index.js", 14 | "sync": "node sync-peer-deps.js" 15 | }, 16 | "keywords": [ 17 | "ecronix", 18 | "rmw-shell", 19 | "react-most-wanted" 20 | ], 21 | "author": "Abdallah", 22 | "license": "MIT" 23 | } 24 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "react-most-wanted-dev", 4 | "prod": "react-most-wanted-3b1b2", 5 | "dev": "react-most-wanted-dev" 6 | } 7 | } -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "rules": "firebase/database.rules.json" 4 | }, 5 | "firestore": { 6 | "rules": "firebase/firestore.rules", 7 | "indexes": "firebase/firestore.indexes.json" 8 | }, 9 | "functions": { 10 | "source": "firebase/functions" 11 | }, 12 | "hosting": { 13 | "public": "build", 14 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 15 | "rewrites": [ 16 | { 17 | "source": "**", 18 | "destination": "/index.html" 19 | } 20 | ], 21 | "headers": [ 22 | { 23 | "source": "/service-worker.js", 24 | "headers": [ 25 | { 26 | "key": "Cache-Control", 27 | "value": "no-cache" 28 | } 29 | ] 30 | } 31 | ] 32 | }, 33 | "storage": { 34 | "rules": "firebase/storage.rules" 35 | }, 36 | "emulators": { 37 | "functions": { 38 | "port": 5001 39 | }, 40 | "firestore": { 41 | "port": 8080 42 | }, 43 | "database": { 44 | "port": 9000 45 | }, 46 | "hosting": { 47 | "port": 5000 48 | }, 49 | "pubsub": { 50 | "port": 8085 51 | }, 52 | "ui": { 53 | "enabled": true 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "indexes": [], 3 | "fieldOverrides": [] 4 | } 5 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .runtimeconfig.json 3 | .firebase-debug.log 4 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/admins/onWrite.f.js: -------------------------------------------------------------------------------- 1 | import * as functions from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | import { setClaim, removeClaim } from '../../utils/customClaims' 4 | 5 | export default functions 6 | .region('europe-west1') 7 | .database.ref('admins/{uid}/') 8 | .onWrite(async (snap, context) => { 9 | const value = snap.after.val() 10 | const uid = context.params.uid 11 | 12 | if (value) { 13 | await admin.firestore().doc(`/admins/${uid}/`).set({ isAdmin: value }) 14 | await setClaim(uid, 'admin') 15 | } else { 16 | await admin.firestore().doc(`/admins/${uid}/`).delete() 17 | await removeClaim(uid, 'admin') 18 | } 19 | 20 | return 21 | }) 22 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/groupChats/members/onCreate.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/group_chats/{groupUid}/members/{uid}') 6 | .onCreate(async (snapshot, context) => { 7 | const { uid, groupUid } = context.params 8 | 9 | const chatSnap = await admin 10 | .database() 11 | .ref(`group_chats/${groupUid}`) 12 | .once('value') 13 | 14 | const { name = 'Grooup chat' } = chatSnap.val() || {} 15 | 16 | await admin 17 | .database() 18 | .ref(`user_chats/${uid}/${groupUid}`) 19 | .update({ 20 | displayName: name, 21 | path: `group_chat_messages/${groupUid}`, 22 | lastMessage: 'Group chat', 23 | }) 24 | 25 | return 26 | }) 27 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/groupChats/members/onDelete.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/group_chats/{groupUid}/members/{uid}') 6 | .onDelete(async (snapshot, context) => { 7 | const { uid, groupUid } = context.params 8 | 9 | await admin.database().ref(`user_chats/${uid}/${groupUid}`).set(null) 10 | 11 | return 12 | }) 13 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/groupChats/name/onUpdate.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/group_chats/{groupUid}/name') 6 | .onUpdate(async (snapshot, context) => { 7 | const { groupUid } = context.params 8 | 9 | const chatSnap = await admin 10 | .database() 11 | .ref(`group_chats/${groupUid}`) 12 | .once('value') 13 | 14 | const { members = {} } = chatSnap.val() || {} 15 | 16 | const name = snapshot.after.val() || '' 17 | const keys = [] 18 | Object.keys(members).map((m) => { 19 | keys.push(m) 20 | }) 21 | 22 | for (let i = 0; i < keys.length; i++) { 23 | const key = keys[i] 24 | 25 | await admin.database().ref(`user_chats/${key}/${groupUid}`).update({ 26 | displayName: name, 27 | }) 28 | } 29 | 30 | return 31 | }) 32 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/publicChats/onCreate.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/public_chats/{taskUid}') 6 | .onCreate((eventSnapshot, context) => { 7 | const authorName = eventSnapshot.child('authorName').val() 8 | const authorPhotoUrl = eventSnapshot.child('authorPhotoUrl').val() 9 | 10 | return admin 11 | .database() 12 | .ref(`/notification_tokens`) 13 | .once('value') 14 | .then(nTokens => { 15 | let registrationTokens = [] 16 | 17 | nTokens.forEach(user => { 18 | user.forEach(token => { 19 | registrationTokens.push(token.key) 20 | }) 21 | }) 22 | 23 | const payload = { 24 | notification: { 25 | title: `${authorName || 'UserName'}`, 26 | body: eventSnapshot.child('message').val(), 27 | icon: authorPhotoUrl || '/apple-touch-icon.png', 28 | click_action: 'https://www.react-most-wanted.com/public_chats', 29 | tag: 'public_chat', 30 | }, 31 | } 32 | 33 | if (registrationTokens.length) { 34 | return admin.messaging().sendToDevice(registrationTokens, payload) 35 | } else { 36 | console.log('Not tokens registered') 37 | } 38 | 39 | return null 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/roles/onWrite.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/roles/{roleUid}') 6 | .onWrite((eventSnap, context) => { 7 | // Exit when the data is not deleted. 8 | if (eventSnap.after.exists()) { 9 | return null 10 | } 11 | 12 | const roleUid = context.params.roleUid 13 | 14 | return admin 15 | .database() 16 | .ref(`role_grants/${roleUid}`) 17 | .remove() 18 | }) 19 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/triggers/onCreate.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | 3 | export default database.ref('/triggers/{uid}').onWrite(snap => { 4 | return snap.after.ref.set(null) 5 | }) 6 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/userChatMessages/onUpdate.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default database 5 | .ref('/user_chat_messages/{senderUid}/{receiverUid}/{messageUid}') 6 | .onUpdate(async (data, context) => { 7 | const { authType, params, timestamp } = context 8 | const { senderUid, receiverUid, messageUid } = params 9 | 10 | if (authType === 'ADMIN') { 11 | return 12 | } 13 | 14 | if (data.after.child('isRead').val() === true) { 15 | await admin 16 | .database() 17 | .ref(`/user_chat_messages/${receiverUid}/${senderUid}/${messageUid}`) 18 | .update({ 19 | isRead: timestamp, 20 | }) 21 | 22 | await admin 23 | .database() 24 | .ref(`/user_chats/${senderUid}/${receiverUid}`) 25 | .update({ isRead: timestamp }) 26 | 27 | await admin 28 | .database() 29 | .ref(`/user_chats/${receiverUid}/${senderUid}`) 30 | .update({ isRead: timestamp }) 31 | } 32 | 33 | return 34 | }) 35 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/userGrants/onWrite.f.js: -------------------------------------------------------------------------------- 1 | import * as functions from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | import { setClaim, removeClaim } from '../../utils/customClaims' 4 | 5 | const wait = (t) => { 6 | return new Promise((resolve, reject) => { 7 | setTimeout(() => resolve(), t) 8 | }) 9 | } 10 | 11 | const random = (min, max) => { 12 | return Math.random() * (max - min) + min 13 | } 14 | 15 | export default functions 16 | .region('europe-west1') 17 | .database.ref('user_grants/{uid}/{grant}') 18 | .onWrite(async (snap, context) => { 19 | const value = snap.after.val() 20 | const { uid, grant } = context.params 21 | 22 | await admin 23 | .firestore() 24 | .doc(`/user_grants/${uid}/`) 25 | .set( 26 | { [grant]: value ? value : admin.firestore.FieldValue.delete() }, 27 | { merge: true } 28 | ) 29 | 30 | console.log('Waiting....') 31 | await wait(random(1000, 4000)) 32 | 33 | if (snap.after.exists() && value.indexOf('storage') !== -1) { 34 | await setClaim(uid, grant) 35 | } else { 36 | await removeClaim(uid, grant) 37 | } 38 | 39 | const user = await admin.auth().getUser(uid) 40 | 41 | console.log('customClaims', Object.keys(user.customClaims).length) 42 | console.log('customClaims', user.customClaims) 43 | 44 | return 45 | }) 46 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/userRoles/onWrite.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | exports = module.exports = database 5 | .ref('/user_roles/{userUid}/{roleUid}') 6 | .onWrite((eventSnapshot, context) => { 7 | const userUid = context.params.userUid 8 | const roleUid = context.params.roleUid 9 | 10 | const roleGrantsRef = admin.database().ref(`role_grants/${roleUid}`) 11 | 12 | return roleGrantsRef.once('value').then(snapshot => { 13 | let promises = [] 14 | 15 | snapshot.forEach(grant => { 16 | let grantRef = false 17 | 18 | console.log('User role changed:', eventSnapshot.after.val()) 19 | 20 | if (eventSnapshot.after.val()) { 21 | grantRef = admin 22 | .database() 23 | .ref(`user_grants/${userUid}/${grant.key}`) 24 | .set(true) 25 | } else { 26 | grantRef = admin 27 | .database() 28 | .ref(`user_grants/${userUid}/${grant.key}`) 29 | .remove() 30 | } 31 | 32 | promises.push(grantRef) 33 | }) 34 | 35 | return Promise.all(promises) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/db/users/onWrite.f.js: -------------------------------------------------------------------------------- 1 | import { database } from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | import splitStringToArray from '../../utils/splitStringToArray' 4 | 5 | exports = module.exports = database 6 | .ref('/users/{userUid}') 7 | .onWrite(async (eventSnapshot, context) => { 8 | const { userUid } = context.params 9 | if (eventSnapshot.after.exists()) { 10 | const { displayName = '', photoURL = '' } = 11 | eventSnapshot.after.val() || {} 12 | await admin 13 | .firestore() 14 | .doc(`/users/${userUid}`) 15 | .set( 16 | { 17 | displayName: displayName || '', 18 | photoURL: photoURL || '', 19 | search: splitStringToArray(displayName || ''), 20 | }, 21 | { merge: true } 22 | ) 23 | } else { 24 | await admin.firestore().doc(`/users/${userUid}/`).delete() 25 | } 26 | }) 27 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | npm-debug.log* 6 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/https/admin/onCall.f.js: -------------------------------------------------------------------------------- 1 | import * as functions from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default functions.https.onCall(async (data, context) => { 5 | const { auth } = context 6 | if (!auth) { 7 | throw new functions.https.HttpsError( 8 | 'failed-precondition', 9 | 'The function must be called ' + 'while authenticated.' 10 | ) 11 | } 12 | 13 | const { uid } = auth 14 | 15 | console.log('uid', uid) 16 | console.log('auth', auth) 17 | 18 | try { 19 | await admin.database().ref(`admins/${uid}`).set(true) 20 | return { message: 'OK' } 21 | } catch (error) { 22 | return error 23 | } 24 | }) 25 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/https/messages/onCall.f.js: -------------------------------------------------------------------------------- 1 | import * as functions from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | 4 | export default functions.https.onCall(async (data, context) => { 5 | if (!context.auth) { 6 | throw new functions.https.HttpsError( 7 | 'failed-precondition', 8 | 'The function must be called ' + 'while authenticated.' 9 | ) 10 | } 11 | 12 | const { payload } = data 13 | console.log('payload', payload) 14 | 15 | try { 16 | const response = await admin.messaging().send(payload) 17 | return { response } 18 | } catch (error) { 19 | return error 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/index.js: -------------------------------------------------------------------------------- 1 | const loadFunctions = require('firebase-function-tools') 2 | const functions = require('firebase-functions') 3 | const admin = require('firebase-admin') 4 | const config = functions.config().firebase 5 | 6 | admin.initializeApp(config) 7 | 8 | loadFunctions(__dirname, exports, true) 9 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "14" 13 | }, 14 | "main": "index.js", 15 | "dependencies": { 16 | "axios": "^0.27.2", 17 | "babel-runtime": "^6.26.0", 18 | "camelcase": "^6.0.0", 19 | "child-process-promise": "^2.2.1", 20 | "firebase-admin": "^10.0.0", 21 | "firebase-function-tools": "^2.0.1", 22 | "firebase-functions": "^3.22.0", 23 | "glob": "^7.1.6", 24 | "mkdirp-promise": "^5.0.1", 25 | "moment": "^2.29.4", 26 | "nodemailer": "^6.7.8", 27 | "request": "^2.88.2", 28 | "request-promise": "^4.2.6", 29 | "uuid": "^8.3.0" 30 | }, 31 | "devDependencies": { 32 | "firebase-functions-test": "^0.3.3", 33 | "path": "^0.12.7" 34 | }, 35 | "private": true 36 | } 37 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/storage/onFinalize.f.js: -------------------------------------------------------------------------------- 1 | import * as functions from 'firebase-functions' 2 | import admin from 'firebase-admin' 3 | import thumbnails from './thumbnails' 4 | 5 | export default functions 6 | .region('europe-west1') 7 | .storage.object() 8 | .onFinalize(async (object, context) => { 9 | const { name, contentType } = object 10 | 11 | if (name.startsWith('users/') && contentType.startsWith('image')) { 12 | return thumbnails(object) 13 | } 14 | 15 | return null 16 | }) 17 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/storage/thumbnails.js: -------------------------------------------------------------------------------- 1 | import admin from 'firebase-admin' 2 | import createThumbnail from 'firebase-function-tools/lib/thumbnail' 3 | 4 | export default async function(object) { 5 | const thumbnail = await createThumbnail(object) 6 | 7 | if (thumbnail) { 8 | const { fileDir, downloadURL } = thumbnail 9 | 10 | await admin 11 | .database() 12 | .ref(fileDir) 13 | .update({ thumbnail: downloadURL }) 14 | } 15 | 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/utils/customClaims.js: -------------------------------------------------------------------------------- 1 | import admin from 'firebase-admin' 2 | 3 | const setClaim = async (uid, name, value = true) => { 4 | const user = await admin.auth().getUser(uid) 5 | 6 | const { [name]: claimName, ...rest } = user.customClaims || {} 7 | 8 | await admin.auth().setCustomUserClaims(uid, { ...rest, [name]: value }) 9 | } 10 | 11 | const removeClaim = async (uid, name) => { 12 | const user = await admin.auth().getUser(uid) 13 | 14 | const { [name]: claimName, ...rest } = user.customClaims || {} 15 | 16 | await admin.auth().setCustomUserClaims(uid, { ...rest }) 17 | } 18 | 19 | export { setClaim, removeClaim } 20 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/utils/splitStringToArray.js: -------------------------------------------------------------------------------- 1 | const MAPPING_TABLE = { 2 | à: 'a', 3 | á: 'a', 4 | â: 'a', 5 | ã: 'a', 6 | å: 'a', 7 | æ: 'ae', 8 | ç: 'c', 9 | è: 'e', 10 | é: 'e', 11 | ê: 'e', 12 | ë: 'e', 13 | ì: 'i', 14 | í: 'i', 15 | î: 'i', 16 | ï: 'i', 17 | ñ: 'n', 18 | ò: 'o', 19 | ó: 'o', 20 | ô: 'o', 21 | õ: 'o', 22 | ù: 'u', 23 | ú: 'u', 24 | û: 'u', 25 | ý: 'y', 26 | ÿ: 'y', 27 | } 28 | 29 | function splitStringToArray(stringToSplit) { 30 | const listCharacters = stringToSplit.split('') 31 | var output = [] 32 | //replace special Characters 33 | for (var i = 0; i < listCharacters.length; i++) { 34 | if (MAPPING_TABLE[listCharacters[i]] != null) { 35 | listCharacters[i] = MAPPING_TABLE[listCharacters[i]] 36 | } 37 | } 38 | for (var i = 0; i < listCharacters.length; i++) { 39 | var temp = [listCharacters[i]] 40 | for (var j = i + 1; j < listCharacters.length; j++) { 41 | temp.push(listCharacters[j]) 42 | const joinedString = temp.join('').toLowerCase() 43 | if (joinedString.length > 2) { 44 | output.push(joinedString) 45 | } 46 | } 47 | } 48 | return output 49 | } 50 | 51 | export default splitStringToArray 52 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/functions/utils/users.js: -------------------------------------------------------------------------------- 1 | const admin = require('firebase-admin') 2 | 3 | // Source: https://firebase.google.com/docs/auth/admin/manage-users 4 | const listAllUsers = (userIds = [], nextPageToken) => { 5 | // List batch of users, 1000 at a time. 6 | return admin 7 | .auth() 8 | .listUsers(1000, nextPageToken) 9 | .then(function (resp) { 10 | if (resp.pageToken) { 11 | // List next batch of users. 12 | return listAllUsers(userIds.concat(resp.users), resp.pageToken) 13 | } 14 | return userIds.concat(resp.users) 15 | }) 16 | .catch(function (error) { 17 | console.log('Error listing users:', error) 18 | }) 19 | } 20 | 21 | export { listAllUsers } 22 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/firebase/storage.rules: -------------------------------------------------------------------------------- 1 | rules_version = '2'; 2 | service firebase.storage { 3 | match /b/{bucket}/o { 4 | match /{allPaths=**} { 5 | allow read, write: if request.auth!=null; 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rmw-shell-template", 3 | "version": "1.0.43", 4 | "description": "This project was bootstrapped with [@ecronix/rmw-shell](https://github.com/ecronix/react-most-wanted)", 5 | "private": "true", 6 | "type": "module", 7 | "scripts": { 8 | "dev": "vite", 9 | "build": "vite build", 10 | "serve": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@ecronix/rmw-shell": "^11.2.82" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react": "^4", 17 | "vite": "^5" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "ISC" 22 | } 23 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/background.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/background.webp -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/bottom.jpg -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/favicon.ico -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/firebase-messaging-sw.js: -------------------------------------------------------------------------------- 1 | // Import and configure the Firebase SDK 2 | // These scripts are made available when the app is served or deployed on Firebase Hosting 3 | // If you do not serve/host your project using Firebase Hosting see https://firebase.google.com/docs/web/setup 4 | importScripts('/__/firebase/7.18.0/firebase-app.js') 5 | importScripts('/__/firebase/7.18.0/firebase-messaging.js') 6 | importScripts('/__/firebase/init.js') 7 | 8 | const messaging = firebase.messaging() 9 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/firebase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/firebase.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/logo192.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/logo512.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "RMW", 3 | "name": "React Most Wanted", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 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 | "src": "maskable_icon.png", 22 | "sizes": "512x512", 23 | "type": "image/png", 24 | "purpose": "any maskable" 25 | } 26 | ], 27 | "start_url": ".", 28 | "display": "standalone", 29 | "theme_color": "#000000", 30 | "background_color": "#ffffff" 31 | } 32 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/maskable_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/maskable_icon.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/material-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/material-ui.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecronix/react-most-wanted/ac59f70f22ad329c127bcf206883651cdee73e4d/packages/rmw-shell/create-rmw-shell/template/public/react.png -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/src/components/Forms/Company.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TextField } from 'mui-rff' 3 | 4 | // eslint-disable-next-line 5 | export default function ({ handleSubmit }) { 6 | return ( 7 |
11 |
40 | 41 | 42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /packages/rmw-shell/create-rmw-shell/template/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/rmw-shell/cypress.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | setupNodeEvents(on, config) { 6 | // implement node event listeners here 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/rmw-shell/cypress/e2e/spec.cy.js: -------------------------------------------------------------------------------- 1 | describe("My React App", () => { 2 | beforeEach(() => { 3 | cy.visit("http://localhost:5173"); 4 | }); 5 | 6 | it("renders the app", () => { 7 | cy.get("#root").should("exist"); 8 | }); 9 | 10 | it('renders "app container top" text', () => { 11 | cy.contains("React Starter-Kit with all the Most Wanted features").should( 12 | "exist" 13 | ); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /packages/rmw-shell/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /packages/rmw-shell/cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -------------------------------------------------------------------------------- /packages/rmw-shell/cypress/support/e2e.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') -------------------------------------------------------------------------------- /packages/rmw-shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 |
11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/rmw-shell/src/components/FormFields/index.tsx: -------------------------------------------------------------------------------- 1 | import { Autocomplete } from "./Autocomplete"; 2 | import { KeyboardDatePicker } from "./KeyboardDatePicker"; 3 | import { TextField } from "./TextField"; 4 | import { DatePicker } from "./DatePicker"; 5 | import { AvatarImage } from "./AvatarImage"; 6 | 7 | export { Autocomplete, KeyboardDatePicker, TextField, DatePicker, AvatarImage }; 8 | -------------------------------------------------------------------------------- /packages/rmw-shell/src/components/Forms/Role.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { TextField } from "mui-rff"; 3 | 4 | export function FormsRole({ handleSubmit }: { handleSubmit: () => void }) { 5 | return ( 6 |
10 |