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,218 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ // Progressive Disclosure Stimulus Controller
4
+ // Handles automatic checking and displaying of progressive features
5
+ //
6
+ // Usage:
7
+ // <div data-controller="progressive-disclosure"
8
+ // data-progressive-disclosure-check-interval-value="60000">
9
+ // </div>
10
+ export default class extends Controller {
11
+ static values = {
12
+ checkInterval: { type: Number, default: 60000 }, // Check every minute
13
+ autoReveal: { type: Boolean, default: true },
14
+ notificationPosition: { type: String, default: 'top-right' }
15
+ }
16
+
17
+ static targets = ['notification', 'featureList']
18
+
19
+ connect() {
20
+ this.checkReadyFeatures()
21
+
22
+ // Set up periodic checking if interval is > 0
23
+ if (this.checkIntervalValue > 0) {
24
+ this.intervalId = setInterval(() => {
25
+ this.checkReadyFeatures()
26
+ }, this.checkIntervalValue)
27
+ }
28
+ }
29
+
30
+ disconnect() {
31
+ if (this.intervalId) {
32
+ clearInterval(this.intervalId)
33
+ }
34
+ }
35
+
36
+ // Check for features that are ready to be revealed
37
+ async checkReadyFeatures() {
38
+ try {
39
+ const response = await fetch('/rails_onboarding/progressive_features/ready', {
40
+ headers: {
41
+ 'Accept': 'application/json',
42
+ 'X-CSRF-Token': this.csrfToken
43
+ }
44
+ })
45
+
46
+ if (!response.ok) return
47
+
48
+ const features = await response.json()
49
+
50
+ if (features && features.length > 0) {
51
+ this.handleReadyFeatures(features)
52
+ }
53
+ } catch (error) {
54
+ console.error('Error checking progressive features:', error)
55
+ }
56
+ }
57
+
58
+ // Handle features that are ready
59
+ handleReadyFeatures(features) {
60
+ if (this.autoRevealValue) {
61
+ // Automatically reveal all ready features
62
+ this.revealAllReady()
63
+ } else {
64
+ // Show notifications for each ready feature
65
+ features.forEach(feature => {
66
+ this.showFeatureNotification(feature)
67
+ })
68
+ }
69
+ }
70
+
71
+ // Show a notification for a new feature
72
+ showFeatureNotification(feature) {
73
+ const notification = this.createNotificationElement(feature)
74
+ document.body.appendChild(notification)
75
+
76
+ // Animate in
77
+ setTimeout(() => {
78
+ notification.classList.add('onboarding-show')
79
+ }, 100)
80
+
81
+ // Auto-dismiss after 10 seconds if not interacted with
82
+ setTimeout(() => {
83
+ if (notification.parentElement) {
84
+ this.dismissNotification(notification)
85
+ }
86
+ }, 10000)
87
+ }
88
+
89
+ // Create notification DOM element
90
+ createNotificationElement(feature) {
91
+ const notification = document.createElement('div')
92
+ notification.className = `progressive-feature-notification ${this.notificationPositionValue}`
93
+ notification.dataset.featureKey = feature.key
94
+
95
+ notification.innerHTML = `
96
+ <div class="notification-content">
97
+ <div class="notification-header">
98
+ <span class="notification-icon">✨</span>
99
+ <h4>${feature.title || 'New Feature Available'}</h4>
100
+ <button class="notification-close" data-action="click->progressive-disclosure#dismissNotification">×</button>
101
+ </div>
102
+ <p>${feature.description || 'A new feature is now available for you!'}</p>
103
+ <div class="notification-actions">
104
+ <button class="onboarding-btn onboarding-btn-primary" data-action="click->progressive-disclosure#revealFeature" data-feature-key="${feature.key}">
105
+ Explore Now
106
+ </button>
107
+ <button class="onboarding-btn onboarding-btn-secondary" data-action="click->progressive-disclosure#dismissNotification">
108
+ Later
109
+ </button>
110
+ </div>
111
+ </div>
112
+ `
113
+
114
+ return notification
115
+ }
116
+
117
+ // Reveal a specific feature
118
+ async revealFeature(event) {
119
+ const featureKey = event.currentTarget.dataset.featureKey
120
+ const notification = event.currentTarget.closest('.progressive-feature-notification')
121
+
122
+ try {
123
+ const response = await fetch(`/rails_onboarding/progressive_features/${featureKey}/reveal`, {
124
+ method: 'POST',
125
+ headers: {
126
+ 'Accept': 'application/json',
127
+ 'Content-Type': 'application/json',
128
+ 'X-CSRF-Token': this.csrfToken
129
+ }
130
+ })
131
+
132
+ if (!response.ok) {
133
+ throw new Error('Failed to reveal feature')
134
+ }
135
+
136
+ const data = await response.json()
137
+
138
+ if (data.success) {
139
+ this.dismissNotification(notification)
140
+
141
+ // Trigger custom event for feature revealed
142
+ this.dispatch('featureRevealed', {
143
+ detail: { feature: data.feature }
144
+ })
145
+
146
+ // Navigate to feature if URL is provided
147
+ if (data.feature && data.feature.url) {
148
+ window.location.href = data.feature.url
149
+ }
150
+ }
151
+ } catch (error) {
152
+ console.error('Error revealing feature:', error)
153
+ }
154
+ }
155
+
156
+ // Reveal all ready features
157
+ async revealAllReady() {
158
+ try {
159
+ const response = await fetch('/rails_onboarding/progressive_features/reveal_all_ready', {
160
+ method: 'POST',
161
+ headers: {
162
+ 'Accept': 'application/json',
163
+ 'Content-Type': 'application/json',
164
+ 'X-CSRF-Token': this.csrfToken
165
+ }
166
+ })
167
+
168
+ if (!response.ok) return
169
+
170
+ const data = await response.json()
171
+
172
+ if (data.success && data.revealed && data.revealed.length > 0) {
173
+ // Dispatch event for all revealed features
174
+ this.dispatch('featuresRevealed', {
175
+ detail: { features: data.revealed }
176
+ })
177
+ }
178
+ } catch (error) {
179
+ console.error('Error revealing features:', error)
180
+ }
181
+ }
182
+
183
+ // Dismiss a notification
184
+ dismissNotification(target) {
185
+ const notification = target.target ? target.currentTarget.closest('.progressive-feature-notification') : target
186
+
187
+ if (!notification) return
188
+
189
+ notification.classList.remove('onboarding-show')
190
+ notification.classList.add('onboarding-hide')
191
+
192
+ setTimeout(() => {
193
+ if (notification.parentElement) {
194
+ notification.remove()
195
+ }
196
+ }, 300)
197
+
198
+ // Track dismissal
199
+ const featureKey = notification.dataset.featureKey
200
+ if (featureKey) {
201
+ fetch(`/rails_onboarding/progressive_features/${featureKey}/dismiss`, {
202
+ method: 'POST',
203
+ headers: {
204
+ 'Accept': 'application/json',
205
+ 'X-CSRF-Token': this.csrfToken
206
+ }
207
+ }).catch(error => {
208
+ console.error('Error tracking dismissal:', error)
209
+ })
210
+ }
211
+ }
212
+
213
+ // Get CSRF token
214
+ get csrfToken() {
215
+ const meta = document.querySelector('meta[name="csrf-token"]')
216
+ return meta ? meta.content : ''
217
+ }
218
+ }