Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ This repository contains code under two different licenses:

The following directories and all their contents are licensed under the **MIT License** (see full text below):

- `lib/react_on_rails/` (excluding `lib/react_on_rails/pro/`)
- `lib/react_on_rails/` (entire directory)
- `packages/react-on-rails/` (entire package)
- All other directories in this repository not explicitly listed as Pro-licensed

### Pro Licensed Code

The following directories and all their contents are licensed under the **React on Rails Pro License**:

- `lib/react_on_rails/pro/`
- `packages/react-on-rails-pro/` (entire package)
- `react_on_rails_pro/` (entire directory)

Expand Down
3 changes: 1 addition & 2 deletions docs/MONOREPO_MERGER_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,11 @@ After the initial merge, the following CI adjustments may be needed:
```md
## MIT License applies to:

- `lib/react_on_rails/` (excluding `lib/react_on_rails/pro/`)
- `lib/react_on_rails/` (entire directory)
- `packages/react-on-rails/` (entire package)

## React on Rails Pro License applies to:

- `lib/react_on_rails/pro/`
- `packages/react-on-rails-pro/` (entire package)
- `react_on_rails_pro/` (entire directory)
```
Expand Down
4 changes: 2 additions & 2 deletions lib/react_on_rails/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
require "react_on_rails/utils"
require "react_on_rails/json_output"
require "active_support/concern"
require "react_on_rails/pro/helper"
require "react_on_rails/pro_helper"

module ReactOnRails
module Helper
include ReactOnRails::Utils::Required
include ReactOnRails::Pro::Helper
include ReactOnRails::ProHelper

COMPONENT_HTML_KEY = "componentHtml"

Expand Down
21 changes: 0 additions & 21 deletions lib/react_on_rails/pro/NOTICE

This file was deleted.

122 changes: 0 additions & 122 deletions lib/react_on_rails/pro/helper.rb

This file was deleted.

53 changes: 0 additions & 53 deletions lib/react_on_rails/pro/utils.rb

This file was deleted.

106 changes: 106 additions & 0 deletions lib/react_on_rails/pro_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# frozen_string_literal: true

module ReactOnRails
module ProHelper
IMMEDIATE_HYDRATION_PRO_WARNING = "[REACT ON RAILS] The 'immediate_hydration' feature requires a " \
"React on Rails Pro license. " \
"Please visit https://shakacode.com/react-on-rails-pro to learn more."

# Generates the complete component specification script tag.
# Handles both immediate hydration (Pro feature) and standard cases.
def generate_component_script(render_options)
# Setup the page_loaded_js, which is the same regardless of prerendering or not!
# The reason is that React is smart about not doing extra work if the server rendering did its job.
component_specification_tag = content_tag(:script,
json_safe_and_pretty(render_options.client_props).html_safe,
type: "application/json",
class: "js-react-on-rails-component",
id: "js-react-on-rails-component-#{render_options.dom_id}",
"data-component-name" => render_options.react_component_name,
"data-trace" => (render_options.trace ? true : nil),
"data-dom-id" => render_options.dom_id,
"data-store-dependencies" =>
render_options.store_dependencies&.to_json,
"data-immediate-hydration" =>
(render_options.immediate_hydration ? true : nil))

# Add immediate invocation script if immediate hydration is enabled
spec_tag = if render_options.immediate_hydration
# Escape dom_id for JavaScript context
escaped_dom_id = escape_javascript(render_options.dom_id)
immediate_script = content_tag(:script, %(
typeof ReactOnRails === 'object' && ReactOnRails.reactOnRailsComponentLoaded('#{escaped_dom_id}');
).html_safe)
"#{component_specification_tag}\n#{immediate_script}"
else
component_specification_tag
end

pro_warning_badge = pro_warning_badge_if_needed(render_options.explicitly_disabled_pro_options)
"#{pro_warning_badge}\n#{spec_tag}".html_safe
end

# Generates the complete store hydration script tag.
# Handles both immediate hydration (Pro feature) and standard cases.
def generate_store_script(redux_store_data)
pro_options_check_result = ReactOnRails::ProUtils.disable_pro_render_options_if_not_licensed(redux_store_data)
redux_store_data = pro_options_check_result[:raw_options]
explicitly_disabled_pro_options = pro_options_check_result[:explicitly_disabled_pro_options]

store_hydration_data = content_tag(:script,
json_safe_and_pretty(redux_store_data[:props]).html_safe,
type: "application/json",
"data-js-react-on-rails-store" => redux_store_data[:store_name].html_safe,
"data-immediate-hydration" =>
(redux_store_data[:immediate_hydration] ? true : nil))

# Add immediate invocation script if immediate hydration is enabled and Pro license is valid
store_hydration_scripts = if redux_store_data[:immediate_hydration]
# Escape store_name for JavaScript context
escaped_store_name = escape_javascript(redux_store_data[:store_name])
immediate_script = content_tag(:script, <<~JS.strip_heredoc.html_safe
typeof ReactOnRails === 'object' && ReactOnRails.reactOnRailsStoreLoaded('#{escaped_store_name}');
JS
)
"#{store_hydration_data}\n#{immediate_script}"
else
store_hydration_data
end

pro_warning_badge = pro_warning_badge_if_needed(explicitly_disabled_pro_options)
"#{pro_warning_badge}\n#{store_hydration_scripts}".html_safe
end

def pro_warning_badge_if_needed(explicitly_disabled_pro_options)
return "" unless explicitly_disabled_pro_options.any?

disabled_features_message = disabled_pro_features_message(explicitly_disabled_pro_options)
warning_message = "[REACT ON RAILS] #{disabled_features_message}\n" \
"Please visit https://shakacode.com/react-on-rails-pro to learn more."
puts warning_message
Rails.logger.warn warning_message

tooltip_text = "#{disabled_features_message} Click to learn more."

<<~HTML.strip
<a href="https://shakacode.com/react-on-rails-pro" target="_blank" rel="noopener noreferrer" title="#{tooltip_text}">
<div style="position: fixed; top: 0; right: 0; width: 180px; height: 180px; overflow: hidden; z-index: 9999; pointer-events: none;">
<div style="position: absolute; top: 50px; right: -40px; transform: rotate(45deg); background-color: rgba(220, 53, 69, 0.85); color: white; padding: 7px 40px; text-align: center; font-weight: bold; font-family: sans-serif; font-size: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.3); pointer-events: auto;">
React On Rails Pro Required
</div>
</div>
</a>
HTML
end

def disabled_pro_features_message(explicitly_disabled_pro_options)
return "".html_safe unless explicitly_disabled_pro_options.any?

feature_list = explicitly_disabled_pro_options.join(", ")
feature_word = explicitly_disabled_pro_options.size == 1 ? "feature" : "features"
"The '#{feature_list}' #{feature_word} " \
"#{explicitly_disabled_pro_options.size == 1 ? 'requires' : 'require'} a " \
"React on Rails Pro license. "
end
end
end
37 changes: 37 additions & 0 deletions lib/react_on_rails/pro_utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

module ReactOnRails
module ProUtils
PRO_ONLY_OPTIONS = %i[immediate_hydration].freeze

# Checks if React on Rails Pro features are available
# @return [Boolean] true if Pro license is valid, false otherwise
def self.support_pro_features?
ReactOnRails::Utils.react_on_rails_pro_licence_valid?
end

def self.disable_pro_render_options_if_not_licensed(raw_options)
if support_pro_features?
return {
raw_options: raw_options,
explicitly_disabled_pro_options: []
}
end

raw_options_after_disable = raw_options.dup

explicitly_disabled_pro_options = PRO_ONLY_OPTIONS.select do |option|
# Use global configuration if it's not overridden in the options
next ReactOnRails.configuration.send(option) if raw_options[option].nil?

raw_options[option]
end
explicitly_disabled_pro_options.each { |option| raw_options_after_disable[option] = false }

{
raw_options: raw_options_after_disable,
explicitly_disabled_pro_options: explicitly_disabled_pro_options
}
end
end
end
Loading
Loading