├── .eslintrc
├── .gitignore
├── LICENSE.md
├── README.md
├── package-lock.json
├── package.json
├── pawconfig.json
├── prod.pawconfig.json
└── src
├── app
├── components
│ └── home
│ │ ├── actions.js
│ │ ├── home.css
│ │ ├── home.js
│ │ └── reducer.js
└── reducers.js
├── client.js
├── resources
└── img
│ ├── Social-Share-Image.png
│ ├── favicon.ico
│ ├── icon-128x128.png
│ ├── icon-144x144.png
│ ├── icon-152x152.png
│ ├── icon-192x192.png
│ ├── icon-384x384.png
│ ├── icon-512x512.png
│ ├── icon-72x72.png
│ ├── icon-96x96.png
│ └── logo.svg
├── routes.js
├── server.js
└── webpack.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/@pawjs/pawjs/.eslintrc"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 |
4 | *.log
5 | npm-debug.log*
6 | yarn-debug.log*
7 | yarn-error.log*
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 | *.pid.lock
14 |
15 | # Directory for instrumented libs generated by jscoverage/JSCover
16 | lib-cov
17 |
18 | # Coverage directory used by tools like istanbul
19 | coverage
20 |
21 | # nyc test coverage
22 | .nyc_output
23 |
24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
25 | .grunt
26 |
27 | # Bower dependency directory (https://bower.io/)
28 | bower_components
29 |
30 | # node-waf configuration
31 | .lock-wscript
32 |
33 | # Compiled binary addons (http://nodejs.org/api/addons.html)
34 | build/Release
35 |
36 | # Dependency directories
37 | node_modules/
38 | jspm_packages/
39 |
40 | # Typescript v1 declaration files
41 | typings/
42 |
43 | # Optional npm cache directory
44 | .npm
45 |
46 | # Optional eslint cache
47 | .eslintcache
48 |
49 | # Optional REPL history
50 | .node_repl_history
51 |
52 | # Output of 'npm pack'
53 | *.tgz
54 |
55 | # Yarn Integrity file
56 | .yarn-integrity
57 |
58 | # dotenv environment variables file
59 | .env
60 |
61 | # WebStorm configurations
62 | .idea
63 |
64 | # Ignore the etc folders created by
65 | etc/
66 |
67 | # Do not add dist to git
68 | dist
69 |
70 | # ignore the config assets as its generated runtime and thus should notbe included in git
71 | src/config/assets.js
72 |
73 | # Ignore sass cache
74 | .sass-cache
75 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Atyantik Technologies Private Limited
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/react-pwa/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
2 |
3 |
4 |
ReactPWA - PawJS & Redux
5 |
6 |
7 | Example repository for integrating REDUX with ReactPWA project. This repo demonstrates the usage & integration of Redux in existing ReactPWA project using Redux.
8 |
9 |
10 | ### Getting Started
11 |
12 | ##### 1. Clone the repo to your local PC and go to the installation
13 | ```bash
14 | git clone https://github.com/Atyantik/example-pawjs-redux.git reactpwa-redux && cd reactpwa-redux
15 | ```
16 |
17 | ##### 2. Install the dependencies
18 | ```bash
19 | npm install
20 | ```
21 |
22 | ##### 2. Start the demo project
23 | ```bash
24 | npm start
25 | ```
26 |
27 | ### Redux
28 | Visit [Redux](https://redux.js.org/) for more details & documentation on Redux
29 |
30 | ### ReactPWA
31 | ReactPWA is a highly scalable, Progressive Web Application foundation, boilerplate, with the best Developer Experience built on top of PawJS
32 | Visit [ReactPWA](https://www.reactpwa.com) for more configuration & documentation.
33 |
34 | ### Backers
35 | Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/react-pwa#backer)]
36 |
37 |
38 |
39 | ### Sponsors
40 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/react-pwa#sponsor)]
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | ### Supporters
54 | ##### Atyantik Technologies Private Limited
55 | Everyone at Atyantik Technologies is contributing their free time for contributing to the project and core discussions.
56 |
57 |
58 |
59 | ### License
60 | This project is licensed under the MIT license, Copyright (c) 2018 [Atyantik Technologies Private Limited](https://www.atyantik.com). For more information see [LICENSE.md](https://github.com/Atyantik/example-pawjs-redux/blob/master/LICENSE.md).
61 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-pawjs-redux",
3 | "version": "1.0.0",
4 | "description": "Example on using Redux with PawJS",
5 | "scripts": {
6 | "start": "pawjs --env=development start",
7 | "build": "pawjs --env=production --config=prod.pawconfig.json build"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/Atyantik/example-pawjs-redux.git"
12 | },
13 | "author": {
14 | "name": "Atyantik Technologies",
15 | "email": "admin@atyantik.com",
16 | "url": "https://www.atyantik.com/"
17 | },
18 | "engines": {
19 | "node": ">=10.11.0"
20 | },
21 | "contributors": [
22 | {
23 | "name": "Tirth Bodawala",
24 | "email": "tirthbodawala@atyantik.com",
25 | "url": "https://www.atyantik.com/"
26 | },
27 | {
28 | "name": "Yash Thakur",
29 | "email": "thakur.yash514@gmail.com",
30 | "url": "http://yashthakur.in/"
31 | }
32 | ],
33 | "devDependencies": {
34 | "@pawjs/pawjs": "^2.2.6",
35 | "@pawjs/redux": "^2.1.6",
36 | "react-redux": "^5.0.7",
37 | "redux": "^4.0.1"
38 | },
39 | "license": "MIT",
40 | "bugs": {
41 | "url": "https://github.com/Atyantik/example-pawjs-redux/issues"
42 | },
43 | "homepage": "https://github.com/Atyantik/example-pawjs-redux#readme",
44 | "dependencies": {
45 | "classnames": "^2.2.6"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/pawconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": "3003",
3 | "host": "0.0.0.0",
4 | "appRootUrl": "/",
5 | "serviceWorker": false,
6 | "serverSideRender": true,
7 | "singlePageApplication": false
8 | }
9 |
--------------------------------------------------------------------------------
/prod.pawconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": "9005",
3 | "host": "0.0.0.0",
4 | "appRootUrl": "/examples/redux",
5 | "serviceWorker": true,
6 | "asyncCSS": false,
7 | "serverSideRender": true,
8 | "singlePageApplication": false
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/components/home/actions.js:
--------------------------------------------------------------------------------
1 | import { INCREMENT_COUNT, DECREMENT_COUNT } from './reducer';
2 |
3 | export const incrementCounter = () => ({
4 | type: INCREMENT_COUNT,
5 | });
6 | export const decrementCounter = () => ({
7 | type: DECREMENT_COUNT,
8 | });
9 |
--------------------------------------------------------------------------------
/src/app/components/home/home.css:
--------------------------------------------------------------------------------
1 | body{
2 | font-family: sans-serif;
3 | }
4 | .container {
5 | text-align: center;
6 | margin-top: 30px;
7 | }
8 | .title {
9 | font-size: 38px;
10 | text-align: left;
11 | margin-bottom: 0;
12 | }
13 | .btn {
14 | margin: 18px;
15 | background-color: #308CBA;
16 | border: none;
17 | padding: 12px 28px;
18 | color: #ffffff;
19 | font-size: 16px;
20 | font-weight: 800;
21 | margin-left: 0;
22 | }
23 | .value {
24 | font-size: 180px;
25 | font-weight: 900;
26 | }
27 | .row{
28 | display: flex;
29 | flex-wrap: wrap;
30 | width: 100%;
31 | justify-content: space-evenly;
32 | align-items: center;
33 | }
34 | .mw500{
35 | max-width: 500px;
36 | margin: 0 auto;
37 | }
38 | .mw800{
39 | max-width: 800px;
40 | margin: 0 auto;
41 | margin-top: 2rem;
42 | border-top: 1px solid #000;
43 | }
44 | .col12{
45 | width: 100%;
46 | float: left;
47 | text-align: left;
48 | }
49 | .col6{
50 | width: 50%;
51 | float: left;
52 | text-align: right;
53 | }
54 | .col8{
55 | width: 60%;
56 | float: left;
57 | text-align: left;
58 | }
59 | .col4{
60 | width: 40%;
61 | float: left;
62 | }
63 | .col6md{
64 | width: 50%;
65 | float: left;
66 | }
67 | .p1 {
68 | padding: 1rem 0;
69 | }
70 | .p2 {
71 | padding: 2rem 0;
72 | }
73 | .mt{
74 | margin-top: 3rem;
75 | }
76 | .black{
77 | background-color: black;
78 | text-decoration: none;
79 | }
80 | .link{
81 | text-decoration: none;
82 | color: #308CBA;
83 | font-weight: 600;
84 | }
85 | @media (max-width: 575px) {
86 | .col6{
87 | width: 100%;
88 | text-align: center;
89 | }
90 | .col4{
91 | width: 100%;
92 | text-align: center;
93 | }
94 | .col8{
95 | width: 100%;
96 | text-align: center;
97 | }
98 | .value{
99 | font-size: 100px;
100 | }
101 | .col12{
102 | text-align: center;
103 | }
104 | .title{
105 | text-align: center;
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/src/app/components/home/home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import _ from 'lodash';
3 | import PropTypes from 'prop-types';
4 | import { connect } from 'react-redux';
5 | import classNames from 'classnames';
6 | import { decrementCounter, incrementCounter } from './actions';
7 |
8 | // import custom CSS
9 | import styles from './home.css';
10 |
11 | export default @connect(state => ({
12 | counterValue: _.get(state.counter, 'count', 0),
13 | }))
14 | class Home extends Component {
15 | static propTypes = {
16 | dispatch: PropTypes.func,
17 | counterValue: PropTypes.number,
18 | };
19 |
20 | static defaultProps = {
21 | dispatch: () => {},
22 | counterValue: 0,
23 | };
24 |
25 | incrementCounter(e) {
26 | const { dispatch } = this.props;
27 | if (e && e.preventDefault) {
28 | e.preventDefault();
29 | }
30 | dispatch(incrementCounter());
31 | }
32 |
33 | decrementCounter(e) {
34 | const { dispatch } = this.props;
35 | if (e && e.preventDefault) {
36 | e.preventDefault();
37 | }
38 | dispatch(decrementCounter());
39 | }
40 |
41 | render() {
42 | const { counterValue } = this.props;
43 | return (
44 |
45 |
46 |
Redux + ReactPWA
47 |
48 |
49 |
50 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | {counterValue}
70 |
71 |
72 |
73 |
74 |
75 |
83 |
137 |
138 | );
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/app/components/home/reducer.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | const initialState = {
4 | count: 5,
5 | };
6 |
7 | export const INCREMENT_COUNT = 'INCREMENT_COUNT';
8 | export const DECREMENT_COUNT = 'DECREMENT_COUNT';
9 |
10 | export const counter = (state = initialState, action) => {
11 | switch (action.type) {
12 | case INCREMENT_COUNT:
13 | return _.assignIn({}, state, {
14 | count: state.count + 1,
15 | });
16 | case DECREMENT_COUNT:
17 | return _.assignIn({}, state, {
18 | count: state.count - 1,
19 | });
20 | default:
21 | return state;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/src/app/reducers.js:
--------------------------------------------------------------------------------
1 | export * from './components/home/reducer';
2 |
--------------------------------------------------------------------------------
/src/client.js:
--------------------------------------------------------------------------------
1 | import ReduxClient from '@pawjs/redux/client';
2 | import * as AppReducers from './app/reducers';
3 |
4 |
5 | const appInitialState = {};
6 |
7 | export default class Client {
8 | trackPageView() {
9 | const { ga } = window;
10 | if (typeof ga !== 'undefined' && ga) {
11 | ga('send', {
12 | hitType: 'pageview',
13 | page: window.location.pathname,
14 | });
15 | }
16 | }
17 |
18 | constructor({ addPlugin }) {
19 | const reduxClient = new ReduxClient({ addPlugin });
20 | reduxClient.setReducers(AppReducers);
21 |
22 | addPlugin(reduxClient);
23 | }
24 |
25 | apply(clientHandler) {
26 | clientHandler
27 | .hooks
28 | .reduxInitialState
29 | .tapPromise('ReduxInitialState', async ({ getInitialState, setInitialState }) => {
30 | const initialState = Object.assign({}, getInitialState(), appInitialState);
31 | setInitialState(initialState);
32 | });
33 |
34 | clientHandler.hooks.renderComplete.tap('InitTracking', () => {
35 | window.ga = window.ga || function () {
36 | (window.ga.q = window.ga.q || []).push(arguments);
37 | };
38 | window.ga.l = +new Date();
39 | window.ga('create', 'UA-108804791-1', 'auto');
40 | window.ga('send', 'pageview', window.location.pathname);
41 | });
42 |
43 | clientHandler.hooks.locationChange.tapPromise('ReInitAds', async () => {
44 | this.trackPageView();
45 | });
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/resources/img/Social-Share-Image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/Social-Share-Image.png
--------------------------------------------------------------------------------
/src/resources/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/favicon.ico
--------------------------------------------------------------------------------
/src/resources/img/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-128x128.png
--------------------------------------------------------------------------------
/src/resources/img/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-144x144.png
--------------------------------------------------------------------------------
/src/resources/img/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-152x152.png
--------------------------------------------------------------------------------
/src/resources/img/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-192x192.png
--------------------------------------------------------------------------------
/src/resources/img/icon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-384x384.png
--------------------------------------------------------------------------------
/src/resources/img/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-512x512.png
--------------------------------------------------------------------------------
/src/resources/img/icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-72x72.png
--------------------------------------------------------------------------------
/src/resources/img/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Atyantik/example-pawjs-redux/663c17acb4a5490c42839a257d6bcb03dd5a3401/src/resources/img/icon-96x96.png
--------------------------------------------------------------------------------
/src/resources/img/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | import ShareImg72 from './resources/img/icon-72x72.png';
2 | import ShareImg96 from './resources/img/icon-96x96.png';
3 | import ShareImg128 from './resources/img/icon-128x128.png';
4 | import ShareImg144 from './resources/img/icon-144x144.png';
5 | import ShareImg152 from './resources/img/icon-152x152.png';
6 | import ShareImg192 from './resources/img/icon-192x192.png';
7 | import ShareImg384 from './resources/img/icon-384x384.png';
8 | import ShareImg512 from './resources/img/icon-512x512.png';
9 | import SocialShareImg from './resources/img/Social-Share-Image.png';
10 |
11 | export default class Routes {
12 | apply(routeHandler) {
13 | const routes = [
14 | {
15 | path: '/',
16 | exact: true,
17 | component: import('./app/components/home/home'),
18 | },
19 | ];
20 |
21 | routeHandler.hooks.initRoutes.tapPromise('AppRoutes', async () => {
22 | routeHandler.addRoutes(routes);
23 | routeHandler.setPwaSchema({
24 | name: 'ReactPWA | PawJS - Redux',
25 | short_name: 'P-Redux',
26 | dir: 'ltr',
27 | lang: 'en-US',
28 | orientation: 'any',
29 | start_url: '/examples/redux',
30 | background_color: '#111',
31 | theme_color: '#111',
32 | display: 'standalone',
33 | description: 'Redux implementation using ReactPWA',
34 | icons: [
35 | {
36 | src: ShareImg72,
37 | sizes: '72x72',
38 | },
39 | {
40 | src: ShareImg96,
41 | sizes: '96x96',
42 | },
43 | {
44 | src: ShareImg128,
45 | sizes: '128x128',
46 | },
47 | {
48 | src: ShareImg144,
49 | sizes: '144x144',
50 | },
51 | {
52 | src: ShareImg152,
53 | sizes: '152x152',
54 | },
55 | {
56 | src: ShareImg192,
57 | sizes: '192x192',
58 | },
59 | {
60 | src: ShareImg384,
61 | sizes: '384x384',
62 | },
63 | {
64 | src: ShareImg512,
65 | sizes: '512x512',
66 | },
67 | ],
68 | });
69 | // eslint-disable-next-line
70 | routeHandler.getDefaultSeoSchema = () => ({
71 | title: 'ReactPWA | Redux',
72 | name: 'ReactPWA | Redux',
73 | description: 'Redux implementation using ReactPWA',
74 | type: 'website',
75 | url: 'https://www.reactpwa.com/examples/redux',
76 | site_name: 'ReactPWA',
77 | image: SocialShareImg,
78 | meta: [
79 | {
80 | name: 'author',
81 | content: 'Yash Thakur',
82 | },
83 | {
84 | name: 'description',
85 | content: 'Redux implementation using ReactPWA',
86 | },
87 | {
88 | name: 'theme-color',
89 | content: '#111',
90 | },
91 | {
92 | name: 'apple-mobile-web-app-status-bar-style',
93 | content: '#111',
94 | },
95 | {
96 | name: 'msapplication-TileColor',
97 | content: '#111',
98 | },
99 | {
100 | name: 'application-name',
101 | content: 'ReactPWA | Redux',
102 | },
103 | {
104 | name: 'generator',
105 | content: 'Redux',
106 | },
107 | {
108 | name: 'apple-mobile-web-app-title',
109 | content: 'ReactPWA | Redux',
110 | }
111 | ],
112 | });
113 | });
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/server.js:
--------------------------------------------------------------------------------
1 | import ReduxServer from '@pawjs/redux/server';
2 | import * as reducers from './app/reducers';
3 | import React from 'react';
4 | import FavIcon from './resources/img/favicon.ico';
5 |
6 | const appInitialState = {};
7 |
8 |
9 | export default class Server {
10 | constructor({ addPlugin }) {
11 | const reduxServer = new ReduxServer({ addPlugin });
12 | reduxServer.setReducers(reducers);
13 | addPlugin(reduxServer);
14 | }
15 |
16 | apply(serverHandler) {
17 | serverHandler
18 | .hooks
19 | .reduxInitialState
20 | .tapPromise('AppInitialState', async ({ getInitialState, setInitialState }) => {
21 | const initialState = Object.assign({}, getInitialState(), appInitialState);
22 | setInitialState(initialState);
23 | });
24 |
25 | serverHandler.hooks.beforeHtmlRender.tap('AddGoogleAnalytics', (Application) => {
26 | Application.htmlProps.head.push(
27 | ,
28 | ,
29 | );
30 | return Application;
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/webpack.js:
--------------------------------------------------------------------------------
1 | export default class ProjectWebpack {}
2 |
--------------------------------------------------------------------------------