rails_onboarding 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +1351 -0
  4. data/Rakefile +6 -0
  5. data/app/assets/javascripts/rails_onboarding/admin/chart_controller.js +25 -0
  6. data/app/assets/javascripts/rails_onboarding/admin/filter_controller.js +49 -0
  7. data/app/assets/javascripts/rails_onboarding/admin/flash_controller.js +21 -0
  8. data/app/assets/javascripts/rails_onboarding/admin/flow_editor_controller.js +86 -0
  9. data/app/assets/javascripts/rails_onboarding/application.js +231 -0
  10. data/app/assets/javascripts/rails_onboarding/milestone_celebration_controller.js +177 -0
  11. data/app/assets/javascripts/rails_onboarding/milestone_dashboard_controller.js +132 -0
  12. data/app/assets/javascripts/rails_onboarding/milestone_detail_controller.js +34 -0
  13. data/app/assets/javascripts/rails_onboarding/navigation_controller.js +277 -0
  14. data/app/assets/javascripts/rails_onboarding/onboarding_controller.js +326 -0
  15. data/app/assets/javascripts/rails_onboarding/progress_controller.js +203 -0
  16. data/app/assets/javascripts/rails_onboarding/progressive_disclosure_controller.js +218 -0
  17. data/app/assets/javascripts/rails_onboarding/tooltip_controller.js +1237 -0
  18. data/app/assets/javascripts/rails_onboarding/tooltip_scheduler_controller.js +511 -0
  19. data/app/assets/javascripts/rails_onboarding/tour_controller.js +763 -0
  20. data/app/assets/stylesheets/rails_onboarding/accessibility.css +536 -0
  21. data/app/assets/stylesheets/rails_onboarding/admin.css +816 -0
  22. data/app/assets/stylesheets/rails_onboarding/application.css +1145 -0
  23. data/app/assets/stylesheets/rails_onboarding/flash_messages.css +237 -0
  24. data/app/assets/stylesheets/rails_onboarding/milestones.css +545 -0
  25. data/app/assets/stylesheets/rails_onboarding/mobile.css +856 -0
  26. data/app/assets/stylesheets/rails_onboarding/progressive_disclosure.css +299 -0
  27. data/app/assets/stylesheets/rails_onboarding/tooltips.css +468 -0
  28. data/app/assets/stylesheets/rails_onboarding/tour.css +495 -0
  29. data/app/assets/stylesheets/rails_onboarding/utilities.css +393 -0
  30. data/app/controllers/concerns/rails_onboarding/admin_authorization.rb +98 -0
  31. data/app/controllers/concerns/rails_onboarding/rate_limitable.rb +104 -0
  32. data/app/controllers/rails_onboarding/ab_tests_controller.rb +257 -0
  33. data/app/controllers/rails_onboarding/admin/ab_tests_controller.rb +121 -0
  34. data/app/controllers/rails_onboarding/admin/base_controller.rb +68 -0
  35. data/app/controllers/rails_onboarding/admin/dashboard_controller.rb +189 -0
  36. data/app/controllers/rails_onboarding/admin/flows_controller.rb +175 -0
  37. data/app/controllers/rails_onboarding/admin/users_controller.rb +366 -0
  38. data/app/controllers/rails_onboarding/application_controller.rb +9 -0
  39. data/app/controllers/rails_onboarding/milestones_controller.rb +126 -0
  40. data/app/controllers/rails_onboarding/onboarding_controller.rb +409 -0
  41. data/app/controllers/rails_onboarding/progressive_features_controller.rb +134 -0
  42. data/app/controllers/rails_onboarding/templates_controller.rb +162 -0
  43. data/app/controllers/rails_onboarding/test_sessions_controller.rb +16 -0
  44. data/app/controllers/rails_onboarding/tooltips_controller.rb +92 -0
  45. data/app/helpers/rails_onboarding/application_helper.rb +4 -0
  46. data/app/helpers/rails_onboarding/i18n_helper.rb +137 -0
  47. data/app/helpers/rails_onboarding/personalization_helper.rb +184 -0
  48. data/app/helpers/rails_onboarding/templates_helper.rb +253 -0
  49. data/app/jobs/rails_onboarding/application_job.rb +4 -0
  50. data/app/mailers/rails_onboarding/application_mailer.rb +6 -0
  51. data/app/mailers/rails_onboarding/onboarding_mailer.rb +72 -0
  52. data/app/models/concerns/rails_onboarding/ab_testable.rb +149 -0
  53. data/app/models/concerns/rails_onboarding/onboardable.rb +649 -0
  54. data/app/models/concerns/rails_onboarding/personalizable.rb +211 -0
  55. data/app/models/concerns/rails_onboarding/progressive_disclosure.rb +276 -0
  56. data/app/models/rails_onboarding/analytics.rb +255 -0
  57. data/app/models/rails_onboarding/analytics_event.rb +168 -0
  58. data/app/models/rails_onboarding/application_record.rb +5 -0
  59. data/app/models/rails_onboarding/flow.rb +41 -0
  60. data/app/services/rails_onboarding/milestone_service.rb +105 -0
  61. data/app/views/layouts/rails_onboarding/admin.html.erb +106 -0
  62. data/app/views/layouts/rails_onboarding/application.html.erb +65 -0
  63. data/app/views/rails_onboarding/ab_tests/index.html.erb +209 -0
  64. data/app/views/rails_onboarding/ab_tests/results.html.erb +253 -0
  65. data/app/views/rails_onboarding/admin/ab_tests/_ab_test_card.html.erb +24 -0
  66. data/app/views/rails_onboarding/admin/ab_tests/index.html.erb +57 -0
  67. data/app/views/rails_onboarding/admin/ab_tests/show.html.erb +41 -0
  68. data/app/views/rails_onboarding/admin/dashboard/index.html.erb +224 -0
  69. data/app/views/rails_onboarding/admin/flows/_form.html.erb +147 -0
  70. data/app/views/rails_onboarding/admin/flows/edit.html.erb +7 -0
  71. data/app/views/rails_onboarding/admin/flows/index.html.erb +125 -0
  72. data/app/views/rails_onboarding/admin/flows/new.html.erb +7 -0
  73. data/app/views/rails_onboarding/admin/flows/preview.html.erb +40 -0
  74. data/app/views/rails_onboarding/admin/flows/show.html.erb +114 -0
  75. data/app/views/rails_onboarding/admin/users/index.html.erb +180 -0
  76. data/app/views/rails_onboarding/admin/users/show.html.erb +187 -0
  77. data/app/views/rails_onboarding/milestones/index.html.erb +64 -0
  78. data/app/views/rails_onboarding/milestones/show.html.erb +57 -0
  79. data/app/views/rails_onboarding/onboarding/_custom_footer.html.erb +2 -0
  80. data/app/views/rails_onboarding/onboarding/_progress_indicator.html.erb +56 -0
  81. data/app/views/rails_onboarding/onboarding/_step_navigation.html.erb +44 -0
  82. data/app/views/rails_onboarding/onboarding/step.html.erb +38 -0
  83. data/app/views/rails_onboarding/onboarding/welcome.html.erb +37 -0
  84. data/app/views/rails_onboarding/onboarding_mailer/completion_email.html.erb +109 -0
  85. data/app/views/rails_onboarding/onboarding_mailer/completion_email.text.erb +29 -0
  86. data/app/views/rails_onboarding/onboarding_mailer/reminder_email.html.erb +99 -0
  87. data/app/views/rails_onboarding/onboarding_mailer/reminder_email.text.erb +20 -0
  88. data/app/views/rails_onboarding/onboarding_mailer/step_completed_email.html.erb +105 -0
  89. data/app/views/rails_onboarding/onboarding_mailer/step_completed_email.text.erb +19 -0
  90. data/app/views/rails_onboarding/onboarding_mailer/welcome_email.html.erb +74 -0
  91. data/app/views/rails_onboarding/onboarding_mailer/welcome_email.text.erb +17 -0
  92. data/app/views/rails_onboarding/shared/_flash.html.erb +25 -0
  93. data/app/views/rails_onboarding/shared/_milestone_badge.html.erb +22 -0
  94. data/app/views/rails_onboarding/shared/_milestone_celebration.html.erb +44 -0
  95. data/app/views/rails_onboarding/shared/_onboarding_banner.html.erb +48 -0
  96. data/app/views/rails_onboarding/templates/index.html.erb +255 -0
  97. data/config/importmap.rb +33 -0
  98. data/config/locales/en.yml +62 -0
  99. data/config/locales/es.yml +62 -0
  100. data/config/locales/fr.yml +62 -0
  101. data/config/routes.rb +79 -0
  102. data/lib/generators/rails_onboarding/install_generator.rb +124 -0
  103. data/lib/generators/rails_onboarding/templates/README +120 -0
  104. data/lib/generators/rails_onboarding/templates/add_analytics_to_rails_onboarding.rb +33 -0
  105. data/lib/generators/rails_onboarding/templates/add_milestone_tracking_to_users.rb +38 -0
  106. data/lib/generators/rails_onboarding/templates/add_onboarding_indexes.rb +93 -0
  107. data/lib/generators/rails_onboarding/templates/add_onboarding_to_users.rb +51 -0
  108. data/lib/generators/rails_onboarding/templates/add_robustness_fields_to_users.rb.tt +20 -0
  109. data/lib/generators/rails_onboarding/templates/create_rails_onboarding_flows.rb +18 -0
  110. data/lib/generators/rails_onboarding/templates/onboarding.css +18 -0
  111. data/lib/generators/rails_onboarding/templates/rails_onboarding.rb +75 -0
  112. data/lib/generators/rails_onboarding/update_generator.rb +73 -0
  113. data/lib/rails_onboarding/api_mode.rb +367 -0
  114. data/lib/rails_onboarding/backfill.rb +130 -0
  115. data/lib/rails_onboarding/background_jobs.rb +412 -0
  116. data/lib/rails_onboarding/caching.rb +180 -0
  117. data/lib/rails_onboarding/cdn_support.rb +202 -0
  118. data/lib/rails_onboarding/configuration/ab_testing.rb +24 -0
  119. data/lib/rails_onboarding/configuration/analytics.rb +29 -0
  120. data/lib/rails_onboarding/configuration/integrations.rb +31 -0
  121. data/lib/rails_onboarding/configuration/milestones.rb +92 -0
  122. data/lib/rails_onboarding/configuration/personalization.rb +25 -0
  123. data/lib/rails_onboarding/configuration/progressive_disclosure.rb +41 -0
  124. data/lib/rails_onboarding/configuration/rate_limiting.rb +18 -0
  125. data/lib/rails_onboarding/configuration/steps.rb +121 -0
  126. data/lib/rails_onboarding/configuration/templates.rb +85 -0
  127. data/lib/rails_onboarding/configuration/tooltips.rb +32 -0
  128. data/lib/rails_onboarding/configuration.rb +133 -0
  129. data/lib/rails_onboarding/configuration_errors.rb +19 -0
  130. data/lib/rails_onboarding/configuration_validator.rb +477 -0
  131. data/lib/rails_onboarding/controller_helpers.rb +153 -0
  132. data/lib/rails_onboarding/current.rb +13 -0
  133. data/lib/rails_onboarding/deprecation.rb +64 -0
  134. data/lib/rails_onboarding/devise_integration.rb +122 -0
  135. data/lib/rails_onboarding/engine.rb +245 -0
  136. data/lib/rails_onboarding/error_recovery.rb +173 -0
  137. data/lib/rails_onboarding/lazy_loading.rb +155 -0
  138. data/lib/rails_onboarding/multi_tenant.rb +306 -0
  139. data/lib/rails_onboarding/requirements_validator.rb +315 -0
  140. data/lib/rails_onboarding/responsive_helper.rb +218 -0
  141. data/lib/rails_onboarding/session_manager.rb +187 -0
  142. data/lib/rails_onboarding/skip_logic.rb +159 -0
  143. data/lib/rails_onboarding/turbo_compatibility.rb +229 -0
  144. data/lib/rails_onboarding/version.rb +3 -0
  145. data/lib/rails_onboarding.rb +44 -0
  146. data/lib/tasks/rails_onboarding_analytics.rake +136 -0
  147. data/lib/tasks/rails_onboarding_tasks.rake +162 -0
  148. metadata +303 -0
@@ -0,0 +1,72 @@
1
+ module RailsOnboarding
2
+ class OnboardingMailer < ApplicationMailer
3
+ include RailsOnboarding::Engine.routes.url_helpers
4
+
5
+ default from: -> { RailsOnboarding.configuration.mailer_from || "noreply@example.com" }
6
+
7
+ def default_url_options
8
+ if defined?(Rails) && Rails.application
9
+ Rails.application.config.action_mailer.default_url_options || { host: "localhost", port: 3000 }
10
+ else
11
+ { host: "localhost", port: 3000 }
12
+ end
13
+ end
14
+
15
+ def welcome_email(user)
16
+ @user = user
17
+ @onboarding_url = onboarding_url
18
+
19
+ mail(
20
+ to: user.email,
21
+ subject: I18n.t("rails_onboarding.mailer.welcome.subject", default: "Welcome! Get Started")
22
+ ) do |format|
23
+ format.text
24
+ format.html
25
+ end
26
+ end
27
+
28
+ def reminder_email(user)
29
+ @user = user
30
+ @current_step = user.onboarding_current_step
31
+ @progress = user.onboarding_progress_percentage
32
+ @onboarding_url = onboarding_url
33
+
34
+ mail(
35
+ to: user.email,
36
+ subject: I18n.t("rails_onboarding.mailer.reminder.subject", default: "Complete Your Onboarding")
37
+ ) do |format|
38
+ format.text
39
+ format.html
40
+ end
41
+ end
42
+
43
+ def completion_email(user)
44
+ @user = user
45
+ @completed_at = user.onboarding_completed_at
46
+ @milestone_points = user.respond_to?(:milestone_points) ? user.milestone_points : 0
47
+
48
+ mail(
49
+ to: user.email,
50
+ subject: I18n.t("rails_onboarding.mailer.completion.subject", default: "Congratulations! Onboarding Complete")
51
+ ) do |format|
52
+ format.text
53
+ format.html
54
+ end
55
+ end
56
+
57
+ def step_completed_email(user)
58
+ @user = user
59
+ @step = user.onboarding_current_step
60
+ @progress = user.onboarding_progress_percentage
61
+ @onboarding_url = onboarding_url
62
+
63
+ mail(
64
+ to: user.email,
65
+ subject: I18n.t("rails_onboarding.mailer.step_completed.subject", default: "Step Completed!")
66
+ ) do |format|
67
+ format.text
68
+ format.html
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOnboarding
4
+ # Concern for A/B testing capabilities on User models
5
+ # Provides methods to assign users to test variants and track their performance
6
+ #
7
+ # @example Include in your User model
8
+ # class User < ApplicationRecord
9
+ # include RailsOnboarding::Onboardable
10
+ # include RailsOnboarding::AbTestable
11
+ # end
12
+ #
13
+ # @example Configure A/B tests
14
+ # RailsOnboarding.configure do |config|
15
+ # config.ab_tests = {
16
+ # onboarding_flow: {
17
+ # variants: ['original', 'simplified', 'gamified'],
18
+ # weights: [50, 25, 25], # Percentage distribution
19
+ # enabled: true
20
+ # }
21
+ # }
22
+ # end
23
+ module AbTestable
24
+ extend ActiveSupport::Concern
25
+
26
+ included do
27
+ # Store A/B test assignments as JSON
28
+ # Expected column: ab_test_assignments (jsonb or text)
29
+ serialize :ab_test_assignments, coder: JSON unless column_names.include?("ab_test_assignments") && columns_hash["ab_test_assignments"].type == :jsonb
30
+
31
+ # Callbacks
32
+ after_initialize :assign_ab_test_variants, if: :new_record?
33
+ end
34
+
35
+ # Get the variant for a specific A/B test
36
+ #
37
+ # @param test_name [String, Symbol] Name of the A/B test
38
+ # @return [String, nil] The assigned variant name or nil if not assigned
39
+ #
40
+ # @example
41
+ # user.ab_test_variant(:onboarding_flow)
42
+ # # => "simplified"
43
+ def ab_test_variant(test_name)
44
+ return nil unless ab_test_assignments.is_a?(Hash)
45
+
46
+ ab_test_assignments[test_name.to_s]
47
+ end
48
+
49
+ # Check if user is in a specific variant
50
+ #
51
+ # @param test_name [String, Symbol] Name of the A/B test
52
+ # @param variant_name [String, Symbol] Name of the variant to check
53
+ # @return [Boolean] True if user is in the specified variant
54
+ #
55
+ # @example
56
+ # user.in_variant?(:onboarding_flow, :simplified)
57
+ # # => true
58
+ def in_variant?(test_name, variant_name)
59
+ ab_test_variant(test_name) == variant_name.to_s
60
+ end
61
+
62
+ # Assign a specific variant to the user (useful for manual assignment)
63
+ #
64
+ # @param test_name [String, Symbol] Name of the A/B test
65
+ # @param variant_name [String, Symbol] Name of the variant to assign
66
+ # @return [Boolean] True if assignment was successful
67
+ #
68
+ # @example
69
+ # user.assign_variant(:onboarding_flow, :gamified)
70
+ def assign_variant(test_name, variant_name)
71
+ self.ab_test_assignments ||= {}
72
+ self.ab_test_assignments[test_name.to_s] = variant_name.to_s
73
+ save if persisted?
74
+ end
75
+
76
+ # Get all A/B test assignments for this user
77
+ #
78
+ # @return [Hash] Hash of test_name => variant_name
79
+ def all_ab_test_assignments
80
+ ab_test_assignments || {}
81
+ end
82
+
83
+ # Track a conversion for an A/B test
84
+ #
85
+ # @param test_name [String, Symbol] Name of the A/B test
86
+ # @param event_name [String, Symbol] Name of the conversion event
87
+ # @param metadata [Hash] Additional metadata to track
88
+ #
89
+ # @example
90
+ # user.track_ab_conversion(:onboarding_flow, :completed, { time_spent: 300 })
91
+ def track_ab_conversion(test_name, event_name, metadata = {})
92
+ variant = ab_test_variant(test_name)
93
+ return unless variant
94
+
95
+ # Track using analytics system if available
96
+ if respond_to?(:track_analytics_event)
97
+ track_analytics_event(
98
+ "ab_test_conversion",
99
+ {
100
+ test_name: test_name.to_s,
101
+ variant: variant,
102
+ event_name: event_name.to_s
103
+ }.merge(metadata)
104
+ )
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ # Automatically assign variants for all enabled A/B tests on user creation
111
+ def assign_ab_test_variants
112
+ self.ab_test_assignments ||= {}
113
+
114
+ ab_tests = RailsOnboarding.configuration.ab_tests || {}
115
+
116
+ ab_tests.each do |test_name, config|
117
+ next unless config[:enabled]
118
+ next if ab_test_assignments[test_name.to_s].present?
119
+
120
+ variant = select_variant(config[:variants], config[:weights])
121
+ ab_test_assignments[test_name.to_s] = variant
122
+ end
123
+ end
124
+
125
+ # Select a variant based on weights
126
+ #
127
+ # @param variants [Array<String>] Available variants
128
+ # @param weights [Array<Integer>] Percentage weights for each variant
129
+ # @return [String] Selected variant name
130
+ def select_variant(variants, weights = nil)
131
+ return variants.sample if weights.nil? || weights.empty?
132
+
133
+ # Normalize weights to ensure they sum to 100
134
+ total_weight = weights.sum.to_f
135
+ normalized_weights = weights.map { |w| (w / total_weight * 100).to_i }
136
+
137
+ # Generate random number and select variant
138
+ random = rand(100)
139
+ cumulative = 0
140
+
141
+ variants.each_with_index do |variant, index|
142
+ cumulative += normalized_weights[index]
143
+ return variant if random < cumulative
144
+ end
145
+
146
+ variants.last # Fallback to last variant
147
+ end
148
+ end
149
+ end