diff --git a/package.json b/package.json index 9684f55..5c622ea 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "react-async-bootstrapper": "2.1.1", "react-async-component": "2.0.0", "react-dom": "16.6.3", + "react-helmet": "5.2.0", "react-hot-loader": "4.3.12", "react-redux": "5.1.1", "react-router-dom": "4.3.1", @@ -84,6 +85,7 @@ "@types/prop-types": "15.5.6", "@types/react": "16.4.18", "@types/react-dom": "16.0.9", + "@types/react-helmet": "5.0.7", "@types/react-redux": "6.0.9", "@types/react-router-dom": "4.3.1", "@types/redux": "3.6.0", diff --git a/src/index.html b/src/index.html index b20bbad..b9aee7b 100755 --- a/src/index.html +++ b/src/index.html @@ -2,8 +2,8 @@ - {title} - + {title} + {meta} { readonly form: FormReducer; - readonly metaReducer: IMetaReducerState; readonly modalReducer: IModalReducerState; readonly renderReducer: IRenderReducerState; readonly userReducer: IUserReducerState; diff --git a/src/stores/meta/IMetaReducerState.ts b/src/stores/meta/IMetaReducerState.ts deleted file mode 100644 index bc5eee8..0000000 --- a/src/stores/meta/IMetaReducerState.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default interface IMetaReducerState { - readonly title: string; - readonly description?: string; -} diff --git a/src/stores/meta/MetaAction.ts b/src/stores/meta/MetaAction.ts deleted file mode 100644 index 2acd317..0000000 --- a/src/stores/meta/MetaAction.ts +++ /dev/null @@ -1,19 +0,0 @@ -import IAction from '../IAction'; -import ITitleDescription from './models/ITitleDescription'; - -export default class MetaAction { - - public static readonly SET_META: string = 'MetaAction.SET_META'; - - public static setMeta(meta: ITitleDescription): IAction { - if (global.document) { - global.document.title = meta.title; - } - - return { - type: MetaAction.SET_META, - payload: meta, - }; - } - -} diff --git a/src/stores/meta/MetaReducer.ts b/src/stores/meta/MetaReducer.ts deleted file mode 100644 index 2bfed3f..0000000 --- a/src/stores/meta/MetaReducer.ts +++ /dev/null @@ -1,30 +0,0 @@ -import MetaAction from './MetaAction'; -import IMetaReducerState from './IMetaReducerState'; -import IAction from '../IAction'; -import ITitleDescription from './models/ITitleDescription'; - -export default class MetaReducer { - - private static readonly _initialState: IMetaReducerState = { - title: 'Robert is cool', - description: '', - }; - - public static reducer(state: IMetaReducerState = MetaReducer._initialState, action: IAction): IMetaReducerState { - switch (action.type) { - case MetaAction.SET_META: - return MetaReducer._setMeta(state, action); - default: - return state; - } - } - - private static _setMeta(state: IMetaReducerState, action: IAction): IMetaReducerState { - return { - ...state, - description: action.payload.description || '', - title: action.payload.title, - }; - } - -} diff --git a/src/stores/meta/models/ITitleDescription.ts b/src/stores/meta/models/ITitleDescription.ts deleted file mode 100644 index e13d6c0..0000000 --- a/src/stores/meta/models/ITitleDescription.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default interface ITitleDescription { - readonly description?: string; - readonly title: string; -} diff --git a/src/stores/rootReducer.ts b/src/stores/rootReducer.ts index bb9a62c..49f3e7c 100755 --- a/src/stores/rootReducer.ts +++ b/src/stores/rootReducer.ts @@ -1,7 +1,6 @@ import {combineReducers, Reducer, ReducersMapObject} from 'redux'; import {connectRouter} from 'connected-react-router'; import UserReducer from './user/UserReducer'; -import MetaReducer from './meta/MetaReducer'; import {reducer as formReducer} from 'redux-form'; import RenderReducer from './render/RenderReducer'; import IStore from './IStore'; @@ -11,7 +10,6 @@ import {History} from 'history'; export default (history: History): Reducer => { const reducerMap: ReducersMapObject = { form: formReducer, - metaReducer: MetaReducer.reducer, modalReducer: ModalReducer.reducer, renderReducer: RenderReducer.reducer, userReducer: UserReducer.reducer, diff --git a/src/views/about/About.tsx b/src/views/about/About.tsx index 926ae3f..27510f7 100644 --- a/src/views/about/About.tsx +++ b/src/views/about/About.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import {connect} from 'react-redux'; -import MetaAction from '../../stores/meta/MetaAction'; import IStore from '../../stores/IStore'; import {Dispatch} from 'redux'; import IAction from '../../stores/IAction'; +import {Helmet} from 'react-helmet'; interface IState {} interface IProps {} @@ -19,13 +19,13 @@ const mapDispatchToProps = (dispatch: Dispatch>): IDispatchToProps class About extends React.Component { - public componentWillMount(): void { - this.props.dispatch(MetaAction.setMeta({title: 'About Page'})); - } - public render(): JSX.Element { return (
+ + About Page + +

{'About'}

{'This is a React Universal application that uses the libraries below.'}

diff --git a/src/views/contact/Contact.tsx b/src/views/contact/Contact.tsx index 1bbe2de..25141ac 100644 --- a/src/views/contact/Contact.tsx +++ b/src/views/contact/Contact.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import {connect} from 'react-redux'; -import MetaAction from '../../stores/meta/MetaAction'; import {Dispatch} from 'redux'; import IStore from '../../stores/IStore'; import ContactForm from './ContactForm'; import IAction from '../../stores/IAction'; +import {Helmet} from 'react-helmet'; interface IState {} interface IProps {} @@ -20,13 +20,13 @@ const mapDispatchToProps = (dispatch: Dispatch>): IDispatchToProps class Contact extends React.Component { - public componentWillMount(): void { - this.props.dispatch(MetaAction.setMeta({title: 'Contact Page'})); - } - public render(): JSX.Element { return (
+ + Contact Page + +

{'Contact'}

{'This contact form uses redux-form to do client-side validation.'}

diff --git a/src/views/errors/NotFound.tsx b/src/views/errors/NotFound.tsx index f7ac57d..50bdf49 100644 --- a/src/views/errors/NotFound.tsx +++ b/src/views/errors/NotFound.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import {connect} from 'react-redux'; -import MetaAction from '../../stores/meta/MetaAction'; import IStore from '../../stores/IStore'; import {Dispatch} from 'redux'; import IAction from '../../stores/IAction'; +import {Helmet} from 'react-helmet'; interface IState {} interface IProps {} @@ -19,13 +19,13 @@ const mapDispatchToProps = (dispatch: Dispatch>): IDispatchToProps class NotFound extends React.Component { - public componentWillMount(): void { - this.props.dispatch(MetaAction.setMeta({title: '404 Page Not Found'})); - } - public render() { return (
+ + 404 Page + +

{'404'}

{'We are sorry but the page you are looking for does not exist.'}

diff --git a/src/views/home/Home.tsx b/src/views/home/Home.tsx index d36e5d7..a528050 100644 --- a/src/views/home/Home.tsx +++ b/src/views/home/Home.tsx @@ -2,7 +2,6 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {push} from 'connected-react-router'; import UserAction from '../../stores/user/UserAction'; -import MetaAction from '../../stores/meta/MetaAction'; import IStore from '../../stores/IStore'; import {Dispatch} from 'redux'; import GenericModalAsync from '../modals/GenericModalAsync'; @@ -12,6 +11,7 @@ import IAction from '../../stores/IAction'; import {IProps as GenericModalProps} from '../modals/GenericModal'; import UserModel from '../../stores/user/models/UserModel'; import * as PropTypes from 'prop-types'; +import {Helmet} from 'react-helmet'; interface IState {} interface IProps {} @@ -44,19 +44,16 @@ class Home extends React.Component + + Home Page + +
{!showLoader && ( <> diff --git a/yarn.lock b/yarn.lock index fdf3902..033e9c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -927,6 +927,13 @@ "@types/node" "*" "@types/react" "*" +"@types/react-helmet@5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-5.0.7.tgz#1cae65b2c37fe54cf56f40cd388836d4619dbc51" + integrity sha512-FbDibfkcGsD/N+3k47bfLcr5uAzSi64LJ2OOILz/P5vtBwT5A92KZAU5H9/7OjhUN6au5k+BbNplhVfp6IXDcQ== + dependencies: + "@types/react" "*" + "@types/react-redux@6.0.9": version "6.0.9" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-6.0.9.tgz#96aa7f5b0716bcc3bfb36ceaa1223118d509f79a" @@ -3279,6 +3286,11 @@ execall@^1.0.0: dependencies: clone-regexp "^1.0.0" +exenv@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= + expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -6782,7 +6794,7 @@ promise@~1.3.0: dependencies: is-promise "~1" -prop-types@15.6.2, prop-types@^15.6.1, prop-types@^15.6.2: +prop-types@15.6.2, prop-types@^15.5.4, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== @@ -6975,6 +6987,16 @@ react-dom@16.6.3: prop-types "^15.6.2" scheduler "^0.11.2" +react-helmet@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7" + integrity sha1-qBgR3yExOm1VxfBYxK66XW89l6c= + dependencies: + deep-equal "^1.0.1" + object-assign "^4.1.1" + prop-types "^15.5.4" + react-side-effect "^1.1.0" + react-hot-loader@4.3.12: version "4.3.12" resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.3.12.tgz#0d56688884e7330c63a00a17217866280616b07a" @@ -7035,6 +7057,14 @@ react-router@^4.3.1: prop-types "^15.6.1" warning "^4.0.1" +react-side-effect@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d" + integrity sha512-Z2ZJE4p/jIfvUpiUMRydEVpQRf2f8GMHczT6qLcARmX7QRb28JDBTpnM2g/i5y/p7ZDEXYGHWg0RbhikE+hJRw== + dependencies: + exenv "^1.2.1" + shallowequal "^1.0.1" + react-tree-walker@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/react-tree-walker/-/react-tree-walker-4.3.0.tgz#b7cae498cebb490281e9e99a01bdb9c6b4926cd3" @@ -7763,7 +7793,7 @@ shallow-clone@^1.0.0: kind-of "^5.0.0" mixin-object "^2.0.1" -shallowequal@^1.0.2: +shallowequal@^1.0.1, shallowequal@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==