Skip to content

Commit 6be2bb2

Browse files
committed
Add Simple Hooks Comment Screen
1 parent ae9d1c7 commit 6be2bb2

File tree

9 files changed

+161
-2
lines changed

9 files changed

+161
-2
lines changed

app/controllers/pages_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def no_router
3333
end
3434

3535
def simple; end
36+
def simple_hooks; end
3637

3738
private
3839

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<h2>Using React (with Hooks) + Rails Backend (with
2+
<a href="https://github.com/shakacode/react_on_rails">react_on_rails gem</a>)</h2>
3+
<p>This example is much simpler than the one using React + Redux and is appropriate when:</p>
4+
<ul>
5+
<li>No or minimal MVC</li>
6+
<li>No async necessary</li>
7+
<li>No server rendering</li>
8+
<li>No pre-population of props</li>
9+
</ul>
10+
<hr/>
11+
12+
<!-- This component is super simple! So no redux, no prerendering. -->
13+
<%= react_component('SimpleHooksCommentScreen', props: {}, prerender: false) %>

client/app/bundles/comments/components/NavigationBar/NavigationBar.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ const NavigationBar = (props) => {
3333
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
3434
<ul className="nav navbar-nav">
3535
<li className={classNames(
36-
{ active: (pathname === paths.ROUTER_PATH || pathname === paths.REACT_ROUTER_PATH) },
37-
)}>
36+
{ active: (pathname === paths.ROUTER_PATH || pathname === paths.REACT_ROUTER_PATH) },
37+
)}>
3838
<a href={paths.ROUTER_PATH}>React Router Demo</a>
3939
</li>
4040
<li className={classNames({ active: (pathname === paths.NO_ROUTER_PATH) })}>
4141
<a href={paths.NO_ROUTER_PATH}>React Demo</a>
4242
</li>
43+
<li className={classNames({ active: (pathname === paths.SIMPLE_HOOKS_REACT_PATH) })}>
44+
<a href={paths.SIMPLE_HOOKS_REACT_PATH}>Simple Hooks React</a>
45+
</li>
4346
<li className={classNames({ active: (pathname === paths.SIMPLE_REACT_PATH) })}>
4447
<a href={paths.SIMPLE_REACT_PATH}>Simple React</a>
4548
</li>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { React, useState, useEffect } from "react";
2+
import request from "axios";
3+
import Immutable from "immutable";
4+
import _ from "lodash";
5+
import ReactOnRails from "react-on-rails";
6+
import { IntlProvider, injectIntl } from "react-intl";
7+
import BaseComponent from 'libs/components/BaseComponent';
8+
import SelectLanguage from "libs/i18n/selectLanguage";
9+
import { defaultMessages, defaultLocale } from "libs/i18n/default";
10+
import { translations } from "libs/i18n/translations";
11+
12+
import CommentForm from "../CommentBox/CommentForm/CommentForm";
13+
import CommentList from "../CommentBox/CommentList/CommentList";
14+
import css from "../SimpleCommentScreen/SimpleCommentScreen.scss";
15+
16+
function SimpleHooksCommentScreen() {
17+
const [comments, setComments] = useState(Immutable.fromJS([]));
18+
const [isSaving, setIsSaving] = useState(false);
19+
const [fetchCommentsError, setFetchCommentsError] = useState(null);
20+
const [submitCommentError, setSubmitCommentError] = usestate(null);
21+
22+
useEffect(() => {
23+
this.fetchComments();
24+
});
25+
26+
function fetchComments() {
27+
return request
28+
.get("comments.json", { responseType: "json" })
29+
.then(res =>
30+
setComments(Immutable.fromJS(res.data.comments))
31+
)
32+
.catch(error => setFetchCommentsError(error));
33+
}
34+
35+
function handleCommentSubmit(comment) {
36+
setIsSaving(true);
37+
38+
const requestConfig = {
39+
responseType: "json",
40+
headers: ReactOnRails.authenticityHeaders()
41+
};
42+
43+
return request
44+
.post("comments.json", { comment }, requestConfig)
45+
.then(() => {
46+
const $$comment = Immutable.fromJS(comment);
47+
setComments(comments.unshift($$comment));
48+
setSubmitCommentError(null);
49+
setIsSaving(false);
50+
})
51+
.catch(error => {
52+
setSubmitCommentError(error)
53+
setIsSaving(false);
54+
});
55+
}
56+
57+
58+
const { handleSetLocale, locale, intl } = this.props;
59+
const { formatMessage } = intl;
60+
const cssTransitionGroupClassNames = {
61+
enter: css.elementEnter,
62+
enterActive: css.elementEnterActive,
63+
leave: css.elementLeave,
64+
leaveActive: css.elementLeaveActive
65+
};
66+
67+
return (
68+
<div className="commentBox container">
69+
<h2>{formatMessage(defaultMessages.comments)}</h2>
70+
{SelectLanguage(handleSetLocale, locale)}
71+
<ul>
72+
<li>{formatMessage(defaultMessages.descriptionSupportMarkdown)}</li>
73+
<li>{formatMessage(defaultMessages.descriptionDeleteRule)}</li>
74+
<li>{formatMessage(defaultMessages.descriptionSubmitRule)}</li>
75+
</ul>
76+
<CommentForm
77+
isSaving={isSaving}
78+
actions={{ submitComment: handleCommentSubmit }}
79+
error={submitCommentError}
80+
cssTransitionGroupClassNames={cssTransitionGroupClassNames}
81+
/>
82+
<CommentList
83+
$$comments={comments}
84+
error={fetchCommentsError}
85+
cssTransitionGroupClassNames={cssTransitionGroupClassNames}
86+
/>
87+
</div>
88+
);
89+
}
90+
91+
export default class I18nWrapper extends BaseComponent {
92+
constructor(props) {
93+
super(props);
94+
95+
this.state = {
96+
locale: defaultLocale
97+
};
98+
99+
_.bindAll(this, "handleSetLocale");
100+
}
101+
102+
handleSetLocale(locale) {
103+
this.setState({ locale });
104+
}
105+
106+
render() {
107+
const { locale } = this.state;
108+
const messages = translations[locale];
109+
const InjectedSimpleHooksCommentScreen = injectIntl(SimpleHooksCommentScreen);
110+
111+
return (
112+
<IntlProvider locale={locale} key={locale} messages={messages}>
113+
<InjectedSimpleHooksCommentScreen
114+
{...this.props}
115+
locale={locale}
116+
handleSetLocale={this.handleSetLocale}
117+
/>
118+
</IntlProvider>
119+
);
120+
}
121+
}

client/app/bundles/comments/constants/paths.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export const ROUTER_PATH = '/';
22
export const REACT_ROUTER_PATH = '/react-router';
33
export const NO_ROUTER_PATH = '/no-router';
44
export const SIMPLE_REACT_PATH = '/simple';
5+
export const SIMPLE_HOOKS_REACT_PATH = '/simple-hooks';
56
export const RAILS_PATH = '/comments';

client/app/bundles/comments/startup/clientRegistration.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import zh from 'react-intl/locale-data/zh';
99
import App from './App';
1010
import RouterApp from './ClientRouterApp';
1111
import SimpleCommentScreen from '../components/SimpleCommentScreen/SimpleCommentScreen';
12+
import SimpleHooksCommentScreen from '../components/SimpleHooksCommentScreen/SimpleHooksCommentScreen';
1213
import routerCommentsStore from '../store/routerCommentsStore';
1314
import commentsStore from '../store/commentsStore';
1415
import NavigationBarApp from './NavigationBarApp';
@@ -25,6 +26,7 @@ ReactOnRails.register({
2526
RouterApp,
2627
NavigationBarApp,
2728
SimpleCommentScreen,
29+
SimpleHooksCommentScreen,
2830
});
2931

3032
ReactOnRails.registerStore({

client/app/bundles/comments/startup/serverRegistration.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ReactOnRails from 'react-on-rails';
44
import App from './App';
55
import RouterApp from './ServerRouterApp';
66
import SimpleCommentScreen from '../components/SimpleCommentScreen/SimpleCommentScreen';
7+
import SimpleHooksCommentScreen from '../components/SimpleHooksCommentScreen/SimpleHooksCommentScreen';
78
import NavigationBarApp from './NavigationBarApp';
89
import routerCommentsStore from '../store/routerCommentsStore';
910
import commentsStore from '../store/commentsStore';
@@ -14,6 +15,7 @@ ReactOnRails.register(
1415
RouterApp,
1516
NavigationBarApp,
1617
SimpleCommentScreen,
18+
SimpleHooksCommentScreen,
1719
},
1820
);
1921

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
root "pages#index"
88

99
get "simple", to: "pages#simple"
10+
get "simple-hooks", to: "pages#simple_hooks"
1011
get "no-router", to: "pages#no_router"
1112

1213
# React Router needs a wildcard

spec/system/add_new_comment_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@
4848
end
4949
end
5050

51+
context "simple hooks page", page: :simple_hooks, js: true, type: :system do
52+
context "via Horizontal Form", form: :horizontal do
53+
include_examples "New Comment Submission", false
54+
include_examples "Validation errors displaying"
55+
end
56+
context "via Inline Form", form: :inline do
57+
include_examples "New Comment Submission", false
58+
include_examples "Validation errors displaying"
59+
end
60+
context "via the Stacked Form", form: :stacked do
61+
include_examples "New Comment Submission", false
62+
include_examples "Validation errors displaying"
63+
end
64+
end
65+
5166
context "from classic page", page: :classic do
5267
background { click_link "New Comment" }
5368
include_examples "New Comment Submission", false

0 commit comments

Comments
 (0)