Skip to content

Commit

Permalink
Merge branch 'development' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
erkobridee committed May 21, 2018
2 parents 1569e80 + db1b2cc commit 37adfe5
Show file tree
Hide file tree
Showing 67 changed files with 2,216 additions and 83 deletions.
7 changes: 5 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"presets": ["env", "react"],
"plugins": ["react-hot-loader/babel"]
"presets": ["env", "react", "stage-2"],
"plugins": [
"react-hot-loader/babel",
["transform-class-properties", { "spec": true }]
]
}
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
MESSAGE="hello world loaded from the .env.example file"
THEME="light"
CLOCK_DISPLAY="12"
LISTEN_SEND_KEYS="off"
LOCALE="en"
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,8 @@ I also keep the webpack configure to consider the file paths from the `./src` di

* [Optimizing front-end delivery with Webpack 4 | Jasel Gadhia](https://jes.al/2018/04/optimizing-front-end-delivery-with-Webpack-4/)

* Project architecture re-ducks: [Scaling your Redux App with ducks | freeCodeCamp](https://medium.freecodecamp.org/scaling-your-redux-app-with-ducks-6115955638be)

* [[GitHub] alexnm / re-ducks](https://github.com/alexnm/re-ducks) - An attempt to extend the original proposal for redux modular architecture

* [[GitHub] FortechRomania / react-redux-complete-example](https://github.com/FortechRomania/react-redux-complete-example) - A react+redux example project based on the re-ducks folder structure
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-socket-simple-chat",
"version": "0.1.0",
"version": "0.2.0",
"description": "a simple chat application that uses react.js, redux and socket.io",
"scripts": {
"start": "webpack-dev-server --mode development --open --hot",
Expand All @@ -22,15 +22,22 @@
"node": ">=8"
},
"dependencies": {
"classnames": "^2.2.5",
"dayjs": "^1.6.3",
"hashids": "^1.1.4",
"prop-types": "^15.6.1",
"react": "^16.3.2",
"react-dom": "^16.3.2"
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"
},
"devDependencies": {
"autoprefixer": "^8.5.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"clean-webpack-plugin": "^0.1.19",
"css-loader": "^0.28.11",
"dotenv-webpack": "^1.5.5",
Expand Down
6 changes: 1 addition & 5 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,4 @@ import { hot } from 'react-hot-loader';

import Chat from 'chat';

const App = () => (
<Chat />
);

export default hot(module)(App);
export default hot(module)(Chat);
44 changes: 44 additions & 0 deletions src/chat/Chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { Component } from 'react';

// using HashRouter that will make the routes work
// over a deployment that hasn't a backend with historyApiFallback support
import { HashRouter } from 'react-router-dom';

import { NavBar } from './containers';
import { Layout, LayoutHeader, LayoutBody } from './components/layout';

import Routes from './Routes';

class Chat extends Component {

render() {

/*
<HashRouter>
<Layout>
<LayoutHeader>
<NavBar />
</LayoutHeader>
<LayoutBody>
<Routes />
</LayoutBody>
</Layout>
</HashRouter>
*/

return (
<HashRouter>
<Layout>
<LayoutHeader>
<NavBar />
</LayoutHeader>
<LayoutBody>
<Routes />
</LayoutBody>
</Layout>
</HashRouter>
);
}
}

export default Chat;
12 changes: 12 additions & 0 deletions src/chat/Routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { Fragment } from 'react';
import { Route, Switch } from 'react-router-dom';
import { ChatRoom, Settings } from './containers';

const Routes = () => (
<Switch>
<Route exact path="/" component={ChatRoom} />
<Route path="/settings" component={Settings} />
</Switch>
);

export default Routes;
2 changes: 2 additions & 0 deletions src/chat/_styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import 'components/styles';
@import 'containers/styles';
1 change: 0 additions & 1 deletion src/chat/components/.gitkeep

This file was deleted.

3 changes: 3 additions & 0 deletions src/chat/components/_styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import 'layout/styles';
@import 'form/styles';
@import 'message/styles';
52 changes: 52 additions & 0 deletions src/chat/components/form/FormGroup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';

/*
usage:
<FormGroup
theme={ theme }
label="labelToTheField"
>
< InputField, InputRadioGroup />
</FormGroup>
*/
class FormGroup extends Component {

// https://reactjs.org/docs/typechecking-with-proptypes.html
static propTypes = {
theme: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
children: PropTypes.element.isRequired
}

// https://reactjs.org/docs/react-without-es6.html#declaring-default-props
static defaultProps = {
theme: 'light'
}

// https://jaketrent.com/post/send-props-to-children-react/
// https://reactjs.org/docs/react-api.html#reactchildren
renderChildren = ( theme, children ) => {
return React.Children.map( children, child => {
return React.cloneElement( child, {
theme
});
});
}

render() {
const { theme, label, children } = this.props;

return (
<div className="form-group">
<div>{ label }</div>
{ this.renderChildren( theme, children ) }
</div>
);
}
}

export default FormGroup;
50 changes: 50 additions & 0 deletions src/chat/components/form/InputField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

/*
usage:
<InputField
theme={ theme }
type={ 'text' | 'password' }
name="sameAttributeNameFromState"
onChange={ this.handleChange }
/>
*/
class InputText extends Component {

// https://reactjs.org/docs/typechecking-with-proptypes.html
static propTypes = {
theme: PropTypes.string,
type: PropTypes.oneOf(['text', 'password']),
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired
}

// https://reactjs.org/docs/react-without-es6.html#declaring-default-props
static defaultProps = {
theme: 'light',
type: 'text'
}

render() {
const { theme, type, className, ...rest } = this.props;

const inputTextClass = classNames(
'form-control',
`form-control--${theme}`,
className
);

return (
<input
className={ inputTextClass }
type={ type }
{ ...rest }
/>
);
}
}

export default InputText;
81 changes: 81 additions & 0 deletions src/chat/components/form/InputRadio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// useful reference about how to define input radio
// http://react.tips/radio-buttons-in-reactjs/

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

/*
usage:
<InputRadio
theme={ theme }
label="Input Radio Label"
name="sameAttributeNameFromState"
value="valueAssignedToTheInputRadio"
selected={ this.state.sameAttributeNameFromState }
onChange={ this.handleChange }
/>
*/
class InputRadio extends Component {

// https://reactjs.org/docs/typechecking-with-proptypes.html
static propTypes = {
theme: PropTypes.string,
label: PropTypes.string,
name: PropTypes.string,
value: PropTypes.string,
selected: PropTypes.string,
onChange: PropTypes.func
}

// https://reactjs.org/docs/react-without-es6.html#declaring-default-props
static defaultProps = {
theme: 'light'
}

handleClick = (event) => {
event.preventDefault();
const { onChange, name, value } = this.props;
if( onChange ) {
onChange({ target: { name, value } });
}
}

render() {
const {
theme, label,
className,
name, value,
selected,
...rest
} = this.props;

const inputRadioClass = classNames(
'form-check',
`form-check--${theme}`,
className
);

return (
<div
className={ inputRadioClass }
onClick={ this.handleClick }>
<input
className="form-check-input"
type="radio"
id={ name }
checked={ value === selected }
{ ...{ name, value, ...rest } }
/>
<label
className="form-check-label"
htmlFor={ name }>
{ label }
</label>
</div>
);
}
}

export default InputRadio;
Loading

0 comments on commit 37adfe5

Please sign in to comment.