diff --git a/Gemfile b/Gemfile
index 75e5aedf..c81935b6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,7 +5,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.2"
-gem "react_on_rails", "14.0.0"
+gem "react_on_rails", path: '../react_on_rails'
gem "shakapacker", "7.2.1"
# Bundle edge Rails instead: gem "rails", github: "rails/rails"
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index d9b9934f..e0ca6a6c 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -33,6 +33,7 @@ def create
format.html { redirect_to @comment, notice: I18n.t("Comment was successfully created.") }
end
format.json { render :show, status: :created, location: @comment }
+ format.turbo_stream
else
if turbo_frame_request?
format.html
@@ -99,6 +100,10 @@ def inline_form
end
end
+ def test_1508
+ @comment = Comment.new
+ end
+
private
def set_comments
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
index c9f6543e..6730abcb 100644
--- a/app/controllers/pages_controller.rb
+++ b/app/controllers/pages_controller.rb
@@ -38,6 +38,10 @@ def simple; end
def rescript; end
+ def hotwired
+ @props = comments_json_string
+ end
+
private
def set_comments
diff --git a/app/views/comments/_form_1508.html.erb b/app/views/comments/_form_1508.html.erb
new file mode 100644
index 00000000..ef4280bc
--- /dev/null
+++ b/app/views/comments/_form_1508.html.erb
@@ -0,0 +1,30 @@
+<%= form_for(@comment, html: { class: "flex flex-col gap-4" }) do |f| %>
+ <% if @comment.errors.any? %>
+
+
<%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:
+
+
+ <% comment.errors.full_messages.each do |message| %>
+ - <%= message %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <%= f.label :author, 'Your Name' %>
+ <%= f.text_field :author, class: "px-3 py-1 leading-4 border border-gray-300 rounded" %>
+
+
+ <%= f.label :text, 'Say something using markdown...' %>
+ <%= f.text_area :text, class: "px-3 py-1 leading-4 border border-gray-300 rounded" %>
+
+
+ <%= f.submit 'Post', class: "self-start px-3 py-1 font-semibold border-0 rounded text-sky-50 bg-sky-600 hover:bg-sky-800 cursor-pointer" %>
+
+
+ Below is a react component which render inside a form (that will proof #1508 is fixed), You can turn-off the flag `force_load` and this below form will not show.
+
+ <%= react_component('HotwiredCommentForm', props: { }, prerender: false, force_load: true) %>
+
+<% end %>
diff --git a/app/views/comments/create.turbo_stream.erb b/app/views/comments/create.turbo_stream.erb
new file mode 100644
index 00000000..3d93e4b7
--- /dev/null
+++ b/app/views/comments/create.turbo_stream.erb
@@ -0,0 +1,10 @@
+<%= turbo_stream.prepend "comments" do %>
+
+
<%= @comment.author %>
+ <%= markdown_to_html(@comment.text) %>
+
+<% end %>
+
+<%= turbo_stream.update "comment-form" do %>
+ <%= link_to "New Comment", new_comment_path, data: {turbo_stream: true} %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/comments/new.turbo_stream.erb b/app/views/comments/new.turbo_stream.erb
new file mode 100644
index 00000000..844cb6dc
--- /dev/null
+++ b/app/views/comments/new.turbo_stream.erb
@@ -0,0 +1,7 @@
+<%= turbo_stream.update "comment-form" do %>
+
+
New Comment
+
+ <%= react_component('HotwiredCommentForm', props: { }, prerender: false, force_load: true) %>
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/comments/test_1508.turbo_stream.erb b/app/views/comments/test_1508.turbo_stream.erb
new file mode 100644
index 00000000..fb704ace
--- /dev/null
+++ b/app/views/comments/test_1508.turbo_stream.erb
@@ -0,0 +1,3 @@
+<%= turbo_stream.replace dom_id(@comment), target: '_top' do %>
+ <%= render partial: 'form_1508' %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/pages/hotwired.html.erb b/app/views/pages/hotwired.html.erb
new file mode 100644
index 00000000..0a9db2a6
--- /dev/null
+++ b/app/views/pages/hotwired.html.erb
@@ -0,0 +1,8 @@
+Demo React Over Hotwired
+
+<%= react_component('HotwiredCommentScreen', props: @props, prerender: false) %>
+
+
+<%= turbo_frame_tag "new_comment" do %>
+ <%= link_to "proof that #1508 fixed", "/test_1508", data: {turbo_stream: true} %>
+<% end %>
\ No newline at end of file
diff --git a/client/app/bundles/comments/components/CommentBox/CommentList/CommentList.jsx b/client/app/bundles/comments/components/CommentBox/CommentList/CommentList.jsx
index 128f8878..cc74ebf3 100644
--- a/client/app/bundles/comments/components/CommentBox/CommentList/CommentList.jsx
+++ b/client/app/bundles/comments/components/CommentBox/CommentList/CommentList.jsx
@@ -78,7 +78,7 @@ export default class CommentList extends BaseComponent {
{this.errorWarning()}
-
+
diff --git a/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentForm.jsx b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentForm.jsx
new file mode 100644
index 00000000..10e89092
--- /dev/null
+++ b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentForm.jsx
@@ -0,0 +1,120 @@
+// eslint-disable-next-line max-classes-per-file
+import React from 'react';
+import request from 'axios';
+import Immutable from 'immutable';
+import _ from 'lodash';
+import ReactOnRails from 'react-on-rails';
+import { IntlProvider, injectIntl } from 'react-intl';
+import BaseComponent from 'libs/components/BaseComponent';
+import SelectLanguage from 'libs/i18n/selectLanguage';
+import { defaultMessages, defaultLocale } from 'libs/i18n/default';
+import { translations } from 'libs/i18n/translations';
+
+import { Turbo } from '@hotwired/turbo-rails';
+import CommentForm from '../CommentBox/CommentForm/CommentForm';
+import css from './HotwiredCommentScreen.module.scss';
+
+class HotwiredCommentForm extends BaseComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isSaving: false,
+ submitCommentError: null,
+ };
+
+ _.bindAll(this, 'handleCommentSubmit');
+ }
+
+ componentDidMount() {
+ }
+
+ handleCommentSubmit(comment) {
+ this.setState({ isSaving: true });
+
+ const requestConfig = {
+ responseType: 'text/vnd.turbo-stream.html',
+ headers: ReactOnRails.authenticityHeaders(),
+ };
+
+ return request
+ .post('comments.turbo_stream', { comment }, requestConfig)
+ .then(r => r.data)
+ .then(html => {
+ Turbo.renderStreamMessage(html)
+ })
+ .then(() => {
+ const { $$comments } = this.state;
+ const $$comment = Immutable.fromJS(comment);
+
+ this.setState({
+ $$comments: $$comments.unshift($$comment),
+ submitCommentError: null,
+ isSaving: false,
+ });
+ })
+ .catch((error) => {
+ this.setState({
+ submitCommentError: error,
+ isSaving: false,
+ });
+ });
+ }
+
+ render() {
+ const { handleSetLocale, locale, intl } = this.props;
+ const cssTransitionGroupClassNames = {
+ enter: css.elementEnter,
+ enterActive: css.elementEnterActive,
+ exit: css.elementLeave,
+ exitActive: css.elementLeaveActive,
+ };
+
+ return (
+
+ {SelectLanguage(handleSetLocale, locale)}
+
+
+
+
+ );
+ }
+}
+
+export default class I18nWrapper extends BaseComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ locale: defaultLocale,
+ };
+
+ _.bindAll(this, 'handleSetLocale');
+ }
+
+ handleSetLocale(locale) {
+ this.setState({ locale });
+ }
+
+ render() {
+ const { locale } = this.state;
+ const messages = translations[locale];
+ const InjectedHotwiredCommentForm = injectIntl(HotwiredCommentForm);
+
+ return (
+
+
+
+ );
+ }
+}
diff --git a/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.jsx b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.jsx
new file mode 100644
index 00000000..94278b42
--- /dev/null
+++ b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.jsx
@@ -0,0 +1,87 @@
+// eslint-disable-next-line max-classes-per-file
+import React from 'react';
+import Immutable from 'immutable';
+import ReactOnRails from 'react-on-rails';
+import { IntlProvider, injectIntl } from 'react-intl';
+import BaseComponent from 'libs/components/BaseComponent';
+import SelectLanguage from 'libs/i18n/selectLanguage';
+import { defaultMessages, defaultLocale } from 'libs/i18n/default';
+import { translations } from 'libs/i18n/translations';
+
+import CommentList from '../CommentBox/CommentList/CommentList';
+import css from './HotwiredCommentScreen.module.scss';
+
+class HotwiredCommentScreen extends BaseComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ $$comments: Immutable.fromJS(props.comments),
+ };
+ }
+
+ componentDidMount() {
+ }
+
+ render() {
+ const { handleSetLocale, locale, intl } = this.props;
+ const { formatMessage } = intl;
+ const cssTransitionGroupClassNames = {
+ enter: css.elementEnter,
+ enterActive: css.elementEnterActive,
+ exit: css.elementLeave,
+ exitActive: css.elementLeaveActive,
+ };
+
+ return (
+
+
+
+ );
+ }
+}
+
+export default class I18nWrapper extends BaseComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ locale: defaultLocale,
+ };
+
+ _.bindAll(this, 'handleSetLocale');
+ }
+
+ handleSetLocale(locale) {
+ this.setState({ locale });
+ }
+
+ render() {
+ const { locale } = this.state;
+ const messages = translations[locale];
+ const InjectedHotwiredCommentScreen = injectIntl(HotwiredCommentScreen);
+
+ return (
+
+
+
+ );
+ }
+}
diff --git a/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.module.scss b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.module.scss
new file mode 100644
index 00000000..c96d339f
--- /dev/null
+++ b/client/app/bundles/comments/components/HotwiredCommentScreen/HotwiredCommentScreen.module.scss
@@ -0,0 +1,17 @@
+.elementEnter {
+ opacity: 0.01;
+
+ &.elementEnterActive {
+ opacity: 1;
+ transition: opacity $animation-duration ease-in;
+ }
+}
+
+.elementLeave {
+ opacity: 1;
+
+ &.elementLeaveActive {
+ opacity: 0.01;
+ transition: opacity $animation-duration ease-in;
+ }
+}
diff --git a/client/app/bundles/comments/components/NavigationBar/NavigationBar.jsx b/client/app/bundles/comments/components/NavigationBar/NavigationBar.jsx
index 65dc3b40..63998104 100644
--- a/client/app/bundles/comments/components/NavigationBar/NavigationBar.jsx
+++ b/client/app/bundles/comments/components/NavigationBar/NavigationBar.jsx
@@ -81,6 +81,14 @@ function NavigationBar(props) {
Simple React
+
+
+ HotWired
+
+
"/cable"
+
+
+ get "test_1508", to: "comments#test_1508", format: :turbo_stream
end