From 3d113e3877f5e026437a3b101add41eb0238957e Mon Sep 17 00:00:00 2001 From: Nuwan Chaturanga Date: Fri, 25 Jul 2025 23:13:21 +0000 Subject: [PATCH] Merged in 5646-test_session_reminder (pull request #66) PLG feature for Test Session reminder emails * PLG feature for Test Session reminder emails Implement the Test Session reminder emails VRFS-5646 * cutoff date for test gear reminder email add cutoff date config to limit the selection after a certain date add batch_size:100 to loops Approved-by: Seth Call --- ...add_test_gear_reminder_columns_to_users.rb | 13 ++++ ruby/lib/jam_ruby/app/mailers/user_mailer.rb | 24 +++++++ .../user_mailer/test_gear_reminder1.html.erb | 26 ++++++++ .../user_mailer/test_gear_reminder1.text.erb | 14 +++++ .../user_mailer/test_gear_reminder2.html.erb | 22 +++++++ .../user_mailer/test_gear_reminder2.text.erb | 12 ++++ .../user_mailer/test_gear_reminder3.html.erb | 26 ++++++++ .../user_mailer/test_gear_reminder3.text.erb | 14 +++++ ruby/lib/jam_ruby/lib/gear_setup_reminder.rb | 2 +- ruby/lib/jam_ruby/lib/test_gear_reminder.rb | 45 +++++++++++++ .../jam_ruby/resque/scheduled/hourly_job.rb | 1 + web/config/application.rb | 2 + web/config/environments/development.rb | 2 + web/config/locales/en.yml | 63 +++++++++++++++++-- 14 files changed, 260 insertions(+), 6 deletions(-) create mode 100644 ruby/db/migrate/20250724161025_add_test_gear_reminder_columns_to_users.rb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.text.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.html.erb create mode 100644 ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.text.erb create mode 100644 ruby/lib/jam_ruby/lib/test_gear_reminder.rb diff --git a/ruby/db/migrate/20250724161025_add_test_gear_reminder_columns_to_users.rb b/ruby/db/migrate/20250724161025_add_test_gear_reminder_columns_to_users.rb new file mode 100644 index 000000000..a1b307bb9 --- /dev/null +++ b/ruby/db/migrate/20250724161025_add_test_gear_reminder_columns_to_users.rb @@ -0,0 +1,13 @@ + class AddTestGearReminderColumnsToUsers < ActiveRecord::Migration + def self.up + execute "ALTER TABLE users ADD COLUMN test_gear_reminder1_sent_at TIMESTAMP" + execute "ALTER TABLE users ADD COLUMN test_gear_reminder2_sent_at TIMESTAMP" + execute "ALTER TABLE users ADD COLUMN test_gear_reminder3_sent_at TIMESTAMP" + end + + def self.down + execute "ALTER TABLE users DROP COLUMN test_gear_reminder1_sent_at" + execute "ALTER TABLE users DROP COLUMN test_gear_reminder2_sent_at" + execute "ALTER TABLE users DROP COLUMN test_gear_reminder3_sent_at" + end + end diff --git a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb index 0f2020854..562d713fd 100644 --- a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb +++ b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb @@ -480,6 +480,30 @@ module JamRuby end end + def test_gear_reminder1(user) + @user = user + mail(:to => user.email, :subject => I18n.t('user_mailer.test_gear_reminder1.subject')) do |format| + format.text + format.html { render layout: "user_mailer_beta" } + end + end + + def test_gear_reminder2(user) + @user = user + mail(:to => user.email, :subject => I18n.t('user_mailer.test_gear_reminder2.subject')) do |format| + format.text + format.html { render layout: "user_mailer_beta" } + end + end + + def test_gear_reminder3(user) + @user = user + mail(:to => user.email, :subject => I18n.t('user_mailer.test_gear_reminder3.subject')) do |format| + format.text + format.html { render layout: "user_mailer_beta" } + end + end + def signup_survey(user) @user = user @subject = I18n.t('user_mailer.signup_survey.subject') diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.html.erb new file mode 100644 index 000000000..5fdbf5254 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.html.erb @@ -0,0 +1,26 @@ +

<%=I18n.t('user_mailer.test_gear_reminder1.greeting') -%> <%= @user.first_name -%> -

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.paragraph1').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.paragraph2').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.paragraph3').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.paragraph4').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.paragraph5').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder1.regards') -%>,
+ <%=I18n.t('user_mailer.test_gear_reminder1.signature') -%> +

\ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.text.erb new file mode 100644 index 000000000..28b5ed287 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder1.text.erb @@ -0,0 +1,14 @@ +<%=I18n.t('user_mailer.test_gear_reminder1.greeting') -%> <%= @user.first_name -%> - + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph1').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph2').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph3').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph4').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph5').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.regards') -%>, +<%=I18n.t('user_mailer.test_gear_reminder1.signature') -%> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.html.erb new file mode 100644 index 000000000..dc297a4c4 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.html.erb @@ -0,0 +1,22 @@ +

<%=I18n.t('user_mailer.test_gear_reminder2.greeting') -%> <%= @user.first_name -%> -

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder2.paragraph1').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder2.paragraph2').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder2.paragraph3').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder2.paragraph4').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder2.regards') -%>,
+ <%=I18n.t('user_mailer.test_gear_reminder2.signature') -%> +

\ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.text.erb new file mode 100644 index 000000000..53bace2af --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder2.text.erb @@ -0,0 +1,12 @@ +<%=I18n.t('user_mailer.test_gear_reminder2.greeting') -%> <%= @user.first_name -%> - + +<%=I18n.t('user_mailer.test_gear_reminder2.paragraph1').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder2.paragraph2').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder2.paragraph3').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder2.paragraph4').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder2.regards') -%>, +<%=I18n.t('user_mailer.test_gear_reminder2.signature') -%> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.html.erb new file mode 100644 index 000000000..c8ab78eca --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.html.erb @@ -0,0 +1,26 @@ +

<%=I18n.t('user_mailer.test_gear_reminder3.greeting') -%> <%= @user.first_name -%> -

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.paragraph1').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.paragraph2').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.paragraph3').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.paragraph4').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.paragraph5').html_safe -%> +

+ +

+ <%=I18n.t('user_mailer.test_gear_reminder3.regards') -%>,
+ <%=I18n.t('user_mailer.test_gear_reminder3.signature') -%> +

\ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.text.erb new file mode 100644 index 000000000..28b5ed287 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/test_gear_reminder3.text.erb @@ -0,0 +1,14 @@ +<%=I18n.t('user_mailer.test_gear_reminder1.greeting') -%> <%= @user.first_name -%> - + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph1').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph2').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph3').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph4').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.paragraph5').html_safe -%> + +<%=I18n.t('user_mailer.test_gear_reminder1.regards') -%>, +<%=I18n.t('user_mailer.test_gear_reminder1.signature') -%> diff --git a/ruby/lib/jam_ruby/lib/gear_setup_reminder.rb b/ruby/lib/jam_ruby/lib/gear_setup_reminder.rb index cc5eb608a..c8e91ce89 100644 --- a/ruby/lib/jam_ruby/lib/gear_setup_reminder.rb +++ b/ruby/lib/jam_ruby/lib/gear_setup_reminder.rb @@ -5,7 +5,7 @@ module JamRuby def self.send_reminders begin - cutoff_date = Date.parse(Rails.application.config.signup_survey_cutoff_date) # Define a cutoff date for the survey/gear setup emails + cutoff_date = Date.parse(Rails.application.config.gear_setup_reminders_effective_from_date) # Define a cutoff date for the survey/gear setup emails reminder1_users(cutoff_date).find_each do |user| UserMailer.gear_setup_reminder1(user).deliver_now diff --git a/ruby/lib/jam_ruby/lib/test_gear_reminder.rb b/ruby/lib/jam_ruby/lib/test_gear_reminder.rb new file mode 100644 index 000000000..aa3afa55a --- /dev/null +++ b/ruby/lib/jam_ruby/lib/test_gear_reminder.rb @@ -0,0 +1,45 @@ +module JamRuby + class TestGearReminder + + @@log = Logging.logger[TestGearReminder] + + def self.send_reminders + begin + cutoff_date = Date.parse(Rails.application.config.test_gear_reminders_effective_from_date) # Define a cutoff date for the test gear setup emails + reminder1_users.find_each(batch_size:100) do |user| + UserMailer.test_gear_reminder1(user).deliver_now + User.where(id: user.id).update_all(test_gear_reminder1_sent_at: Time.now) + end + + reminder2_users.find_each(batch_size:100) do |user| + UserMailer.test_gear_reminder2(user).deliver_now + User.where(id: user.id).update_all(test_gear_reminder2_sent_at: Time.now) + end + + reminder3_users.find_each(batch_size:100) do |user| + UserMailer.test_gear_reminder3(user).deliver_now + User.where(id: user.id).update_all(test_gear_reminder3_sent_at: Time.now) + end + rescue Exception => e + @@log.error("unable to send gear setup reminder email #{e}") + puts "unable to send gear setup reminder email #{e}" + end + end + + def self.prospect_users + User.where("users.first_music_session_at IS NULL") + end + + def self.reminder1_users(cutoff_date) + TestGearReminder.prospect_users.where("users.first_certified_gear_at < ? AND users.created_at >= ? AND users.test_gear_reminder1_sent_at IS NULL", 1.day.ago, cutoff_date) + end + + def self.reminder2_users(cutoff_date) + TestGearReminder.prospect_users.where("users.first_certified_gear_at < ? AND users.created_at >= ? AND users.test_gear_reminder1_sent_at IS NOT NULL AND users.test_gear_reminder2_sent_at IS NULL", 3.days.ago, cutoff_date) + end + + def self.reminder3_users(cutoff_date) + TestGearReminder.prospect_users.where("users.first_certified_gear_at < ? AND users.created_at > ? AND users.test_gear_reminder2_sent_at IS NOT NULL AND users.test_gear_reminder3_sent_at IS NULL", 5.days.ago, cutoff_date) + end + end +end \ No newline at end of file diff --git a/ruby/lib/jam_ruby/resque/scheduled/hourly_job.rb b/ruby/lib/jam_ruby/resque/scheduled/hourly_job.rb index 45606b896..e685f4321 100644 --- a/ruby/lib/jam_ruby/resque/scheduled/hourly_job.rb +++ b/ruby/lib/jam_ruby/resque/scheduled/hourly_job.rb @@ -16,6 +16,7 @@ module JamRuby EmailProfileReminder.send_reminders EmailSignupSurvey.send_survey GearSetupReminder.send_reminders + TestGearReminder.send_reminders ConnectionManager.new.cleanup_dangling @@log.info("done") diff --git a/web/config/application.rb b/web/config/application.rb index 3ca4f1cf5..3ad90d1aa 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -522,6 +522,8 @@ if defined?(Bundler) config.send_user_match_mail_only_to_jamkazam_team = true config.signup_survey_url = "https://www.surveymonkey.com/r/WVBKLYL" config.signup_survey_cutoff_date = "2025-06-10" + config.gear_setup_reminders_effective_from_date = "2025-06-10" + config.test_gear_reminders_effective_from_date = "2025-07-24" config.action_mailer.asset_host = config.action_controller.asset_host end end diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index 858e677b1..4656ca7d4 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -128,4 +128,6 @@ SampleApp::Application.configure do config.send_user_match_mail_only_to_jamkazam_team = false config.signup_survey_url = "https://www.surveymonkey.com/r/WVBKLYL" config.signup_survey_cutoff_date = "2025-06-10" + config.gear_setup_reminders_effective_from_date = "2025-06-10" + config.test_gear_reminders_effective_from_date = "2025-07-24" end diff --git a/web/config/locales/en.yml b/web/config/locales/en.yml index 82453cdb5..ba1c37d74 100644 --- a/web/config/locales/en.yml +++ b/web/config/locales/en.yml @@ -83,7 +83,6 @@ en: paragraph4: "For next steps, don’t forget you can always refer back to the Welcome email we sent you when you signed up. And if you run into any problems or get stuck, please send us email at support@jamkazam.com. We’re always happy to help" regards: "Best Regards," signature: "JamKazam Team" - profile_complete_reminder2: subject: "Complete your JamKazam profile" greeting: "Hello" @@ -92,7 +91,6 @@ en: paragraph2: "For next steps after your profile, don’t forget you can always refer back to the Welcome email we sent you when you signed up. And if you run into any problems or get stuck, please send us email at support@jamkazam.com. We’re always happy to help!" regards: "Best Regards," signature: "JamKazam Team" - profile_complete_reminder3: subject: "Complete your JamKazam profile" greeting: "Hello" @@ -100,7 +98,6 @@ en: update_profile: "Update Profile" regards: "Best Regards," signature: "JamKazam Team" - gear_setup_reminder1: subject: "Set up audio gear in JamKazam now so you can get in your first session" greeting: "Hello" @@ -113,7 +110,6 @@ en: If you have any trouble or feel confused about gear setup, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. regards: "Best Regards," signature: "JamKazam Team" - gear_setup_reminder2: subject: "Set up your gear in JamKazam now to connect with other musicians" greeting: "Hello" @@ -127,7 +123,6 @@ en: If you have any trouble or feel confused about gear setup, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. regards: "Best Regards," signature: "JamKazam Team" - gear_setup_reminder3: subject: Don’t waste your free 30-day premium gold plan - set up your gear now! greeting: "Hello" @@ -143,6 +138,64 @@ en: If you have any trouble or feel confused about gear setup, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. regards: "Best Regards," signature: "JamKazam Team" + test_gear_reminder1: + subject: "Test your gear in a private JamKazam session to get ready to go!" + greeting: "Hello" + paragraph1: | + Now that you have set up your gear, we recommend that you get into a private session alone to test that your gear is working properly and to get familiar with some of the key features you’ll want to use when in a session with other musicians. + paragraph2: | + To get into a private session on your own, we recommend you connect your computer to your home router using an Ethernet cable (just to get into the practice of doing this), and then follow the instructions in this help article to quick start a private session. + paragraph3: | + Once you’re in the session, we recommend you explore the following features: + + paragraph4: | + If you still feel like you want to get more comfortable in online sessions before starting to jump in with others, we offer a weekly office hours JamKazam session every Tuesday 7-8pm US Central Time. You can join this session as a safe space with a JamKazam support team member to experience and learn how to play in online sessions, or to ask questions about particular features or issues you’re having. To find this session, start the JamKazam app, click the Find Session tile, then click the Open Jams tile, and look for the session called “JamKazam Office Hours”, and click the Join icon on this session. + paragraph5: | + If you have any trouble or feel confused while testing things out, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. + regards: "Best Regards," + signature: "JamKazam Team" + test_gear_reminder2: + subject: "Test your gear and learn how to use key features in a private JamKazam" + greeting: "Hello" + paragraph1: "Before hopping into JamKazam sessions with other musicians, we recommend you get into a private session alone to test that your gear is working properly and to get familiar with some of the key features you’ll want to use when in a session with other musicians." + paragraph2: | + To get into a private session on your own, start up the JamKazam app, click the big orange Create Session tile, and then click the Quick Start Private button. This will drop you into a private session alone. Once you’re in the session, we recommend you read/review the help topics on this help page to familiarize yourself with the features explained in these help articles, as you’ll use most of these features. + paragraph3: | + After doing this, if you still feel like you want to get more comfortable in online sessions before starting to jump in with others, we offer a weekly office hours JamKazam session every Tuesday 7-8pm US Central Time. You can join this session as a safe space with a JamKazam support team member to experience and learn how to play in online sessions, or to ask questions about particular features or issues you’re having. To find this session, start the JamKazam app, click the Find Session tile, then click the Open Jams tile, and look for the session called “JamKazam Office Hours”, and click the Join icon on this session. + paragraph4: | + If you have any trouble or feel confused while testing things out, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. + regards: "Best Regards," + signature: "JamKazam Team" + test_gear_reminder3: + subject: "Don’t waste your free 30-day premium gold plan – get in a test session now!" + greeting: "Hello" + paragraph1: "When you sign up for JamKazam, we give you a free 30-day premium gold plan so you can fully experience how amazing our online sessions are and how JamKazam can help you play more music with more people to bring more musical joy to your life." + paragraph2: | + Don’t waste your 30-day window! Test your gear in a private JamKazam session now, so that you’re ready to join sessions and play with other musicians. + paragraph3: | + To get into a private session on your own, start up the JamKazam app, click the big orange Create Session tile, and then click the Quick Start Private button. This will drop you into a private session alone. Once you’re in the session, we recommend you read/review the help topics on this help page to familiarize yourself with the features explained in these help articles, as you’ll use most of these features. + paragraph4: | + After doing this, if you still feel like you want to get more comfortable in online sessions before starting to jump in with others, we offer a weekly office hours JamKazam session every Tuesday 7-8pm US Central Time. You can join this session as a safe space with a JamKazam support team member to experience and learn how to play in online sessions, or to ask questions about particular features or issues you’re having. To find this session, start the JamKazam app, click the Find Session tile, then click the Open Jams tile, and look for the session called “JamKazam Office Hours”, and click the Join icon on this session. + paragraph5: | + If you have any trouble or feel confused while testing things out, you can email us for help at support@jamkazam.com. You can also visit with a JamKazam support team member in our weekly Zoom office hours, which is offered every Wednesday from 11am to 12pm US Central Time. + regards: "Best Regards," + signature: "JamKazam Team" signup_survey: subject: "Let us help you to be successful on JamKazam" greeting: "Hi"