diff --git a/app/controllers/concerns/member_concerns.rb b/app/controllers/concerns/member_concerns.rb index 8c75a43f6..76c5594d0 100644 --- a/app/controllers/concerns/member_concerns.rb +++ b/app/controllers/concerns/member_concerns.rb @@ -9,8 +9,17 @@ module InstanceMethods private def member_params - params.require(:member).permit( - :pronouns, :name, :surname, :email, :mobile, :about_you, :skill_list, :newsletter + params.fetch(:member, {}).permit( + :pronouns, + :name, + :surname, + :email, + :mobile, + :about_you, + :skill_list, + :newsletter, + :how_you_found_us_other_reason, + how_you_found_us: [] ) end diff --git a/app/controllers/member/details_controller.rb b/app/controllers/member/details_controller.rb index 403e460d2..1d3985ba5 100644 --- a/app/controllers/member/details_controller.rb +++ b/app/controllers/member/details_controller.rb @@ -8,13 +8,28 @@ class Member::DetailsController < ApplicationController def edit accept_terms - flash[notice] = I18n.t('notifications.signing_up') @member.newsletter ||= true end def update - return render :edit unless @member.update(member_params) + how_found = Array(member_params[:how_you_found_us]).reject(&:blank?) + other_reason = member_params[:how_you_found_us_other_reason] + + how_found << other_reason if other_reason.present? + how_found.uniq! + member_params_without_other_reason = member_params.to_h.except(:how_you_found_us_other_reason) + + if how_found.blank? + @member.assign_attributes(member_params_without_other_reason) + @member.errors.add(:how_you_found_us, 'You must select at least one option') + return render :edit + end + + attrs = member_params_without_other_reason + attrs[:how_you_found_us] = how_found + + return render :edit unless @member.update(attrs) member_params[:newsletter] ? subscribe_to_newsletter(@member) : unsubscribe_from_newsletter(@member) redirect_to step2_member_path diff --git a/app/views/member/details/edit.html.haml b/app/views/member/details/edit.html.haml index 60bc0fbec..9bfaa6fef 100644 --- a/app/views/member/details/edit.html.haml +++ b/app/views/member/details/edit.html.haml @@ -15,6 +15,18 @@ = f.input :about_you, as: :text, label: t('member.details.edit.coach.about_you'), input_html: { rows: 3 }, required: true - else = f.input :about_you, as: :text, label: t('member.details.edit.student.about_you'), input_html: { rows: 3 }, required: true + - if @member.errors[:how_you_found_us]&.any? + %span.text-danger= @member.errors[:how_you_found_us].first + .col-12.mb-3 + %label{ for: 'how_you_found_us' }= t('member.details.edit.how_you_found_us') + %span * + - options = ['From a friend', 'Search engine (Google etc.)', 'Social Media', "One of Codebar's hosts or partners"] + - options.each do |option| + .form-check + = check_box_tag 'member[how_you_found_us][]', option, false, id: "how_you_found_us_#{option.parameterize}", class: 'form-check-input' + = label_tag "how_you_found_us_#{option.parameterize}", option, class: 'form-check-label', style: 'margin-left: 8px;' + = label_tag :how_you_found_us_other_reason, t('member.details.edit.how_you_found_us_other_reason'), class: 'my-1' + = text_field_tag 'member[how_you_found_us_other_reason]', nil, placeholder: "Please specify how you heard about us", class: 'form-control w-100' = f.input :newsletter, as: :boolean, checked_value: true, unchecked_value: false .text-right.mb-4 = hidden_field_tag :next_page, step2_member_path(member_type: @type) diff --git a/app/views/members/show.html.haml b/app/views/members/show.html.haml index 433b9539a..9b8a4344c 100644 --- a/app/views/members/show.html.haml +++ b/app/views/members/show.html.haml @@ -26,6 +26,14 @@ %dt About %dd.mb-3= @member.about_you + %dt How you found us + - if @member.how_you_found_us.present? + %ul + - @member.how_you_found_us.each do |reason| + %li= reason + - else + %dd Not specified + - if @member.skills.any? %dt Skills %dd.mb-3 diff --git a/config/locales/en.yml b/config/locales/en.yml index 7f3b81ff3..af6cdb5ff 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -442,6 +442,8 @@ en: edit: title: Almost there... summary: We need some more details from you to finish creating your account. We use these to help run our events. + how_you_found_us: "How did you find out about us?" + how_you_found_us_other_reason: "Please specify (if Other)" coach: about_you: What experience do you have? What languages do you like to use? Tell us a little bit about yourself! student: diff --git a/db/migrate/20250823151717_add_how_you_found_us_options.rb b/db/migrate/20250823151717_add_how_you_found_us_options.rb new file mode 100644 index 000000000..cfe4c8fd5 --- /dev/null +++ b/db/migrate/20250823151717_add_how_you_found_us_options.rb @@ -0,0 +1,5 @@ +class AddHowYouFoundUsOptions < ActiveRecord::Migration[7.0] + def change + add_column :members, :how_you_found_us, :text, array: true, default: [] + end +end diff --git a/db/schema.rb b/db/schema.rb index 192b8fd69..a6c772737 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -391,6 +391,7 @@ t.string "pronouns" t.datetime "accepted_toc_at", precision: nil t.datetime "opt_in_newsletter_at", precision: nil + t.text "how_you_found_us", default: [], array: true t.index ["email"], name: "index_members_on_email", unique: true end diff --git a/spec/controllers/member/details_controller_spec.rb b/spec/controllers/member/details_controller_spec.rb new file mode 100644 index 000000000..259c5af9a --- /dev/null +++ b/spec/controllers/member/details_controller_spec.rb @@ -0,0 +1,84 @@ +RSpec.describe Member::DetailsController, type: :controller do + render_views + let(:member) { Fabricate(:member) } + + before do + allow(controller).to receive(:current_user).and_return(member) + end + + describe 'PATCH #update' do + context 'with valid params' do + it 'updates how_you_found_us with checkbox options' do + patch :update, params: { + id: member.id, + member: { + how_you_found_us: ['Social Media', 'From a friend'], + newsletter: 'true' + } + } + + member.reload + expect(member.how_you_found_us).to contain_exactly('Social Media', 'From a friend') + expect(response).to redirect_to(step2_member_path) + end + + it 'adds other_reason to how_you_found_us when provided' do + patch :update, params: { + id: member.id, + member: { + how_you_found_us: ['Search engine (Google etc.)'], + how_you_found_us_other_reason: 'Saw a pamphlet', + newsletter: 'false' + }, + } + + member.reload + expect(member.how_you_found_us).to contain_exactly('Search engine (Google etc.)', 'Saw a pamphlet') + expect(response).to redirect_to(step2_member_path) + end + + it 'updates how_you_found_us with only other_reason' do + patch :update, params: { + id: member.id, + member: { + how_you_found_us: [], + how_you_found_us_other_reason: 'At a meetup', + newsletter: 'true' + }, + } + + member.reload + expect(member.how_you_found_us).to eq(['At a meetup']) + expect(response).to redirect_to(step2_member_path) + end + + it 'removes duplicates and blank entries' do + patch :update, params: { + id: member.id, + member: { + how_you_found_us: ['From a friend', '', 'From a friend'], + how_you_found_us_other_reason: 'From a friend', + newsletter: 'true' + }, + } + + member.reload + expect(member.how_you_found_us).to eq(['From a friend']) + expect(response).to redirect_to(step2_member_path) + end + end + + context 'when update fails (invalid data)' do + it 'renders the edit template' do + patch :update, params: { + id: member.id, + member: { + how_you_found_us: [] + } + } + + expect(response.body).to include('You must select at least one option') + end + end + end +end diff --git a/spec/fabricators/member_fabricator.rb b/spec/fabricators/member_fabricator.rb index 0564bcb48..568589f01 100644 --- a/spec/fabricators/member_fabricator.rb +++ b/spec/fabricators/member_fabricator.rb @@ -4,6 +4,7 @@ surname { Faker::Name.last_name } email { Faker::Internet.email } about_you { Faker::Lorem.sentence } + how_you_found_us { ['From a friend'] } auth_services(count: 1) { Fabricate(:auth_service) } accepted_toc_at { Time.zone.now } end diff --git a/spec/features/member_joining_spec.rb b/spec/features/member_joining_spec.rb index 8cfcf27b7..c2948f9c4 100644 --- a/spec/features/member_joining_spec.rb +++ b/spec/features/member_joining_spec.rb @@ -27,6 +27,7 @@ expect(page).to have_content "Surname can't be blank" expect(page).to have_content "Email address can't be blank" expect(page).to have_content "About you can't be blank" + expect(page).to have_content "You must select at least one option" end scenario 'A new member details are successfully captured' do @@ -40,6 +41,8 @@ fill_in 'member_surname', with: 'Doe' fill_in 'member_email', with: 'jane@codebar.io' fill_in 'member_about_you', with: Faker::Lorem.paragraph + find('#how_you_found_us_from-a-friend').click + fill_in 'member_how_you_found_us_other_reason', with: 'found on a poster', id: true click_on 'Next' expect(page).to have_current_path(step2_member_path) diff --git a/spec/features/member_portal_spec.rb b/spec/features/member_portal_spec.rb index 2d26e0d0a..0e31a2755 100644 --- a/spec/features/member_portal_spec.rb +++ b/spec/features/member_portal_spec.rb @@ -45,6 +45,25 @@ end end + it 'can access and view their profile' do + visit profile_path + + expect(page).to have_content('Details') + expect(page).to have_content(member.full_name) + + expect(page).to have_content('Email') + expect(page).to have_content(member.email) + + expect(page).to have_content('Phone number') + expect(page).to have_content(member.mobile) + + expect(page).to have_content('About') + expect(page).to have_content(member.about_you) + + expect(page).to have_content('How you found us') + expect(page).to have_content(member.how_you_found_us.first) + end + it 'can access and update their profile' do visit profile_path diff --git a/spec/features/subscribing_to_newsletter_spec.rb b/spec/features/subscribing_to_newsletter_spec.rb index 38c24b940..2e5101615 100644 --- a/spec/features/subscribing_to_newsletter_spec.rb +++ b/spec/features/subscribing_to_newsletter_spec.rb @@ -27,6 +27,8 @@ fill_in 'member_surname', with: 'Doe' fill_in 'member_email', with: 'jane@codebar.io' fill_in 'member_about_you', with: Faker::Lorem.paragraph + find('#how_you_found_us_from-a-friend').click + fill_in 'member_how_you_found_us_other_reason', with: Faker::Lorem.paragraph, id: true click_on 'Next' end @@ -46,6 +48,8 @@ fill_in 'member_surname', with: 'Doe' fill_in 'member_email', with: 'jane@codebar.io' fill_in 'member_about_you', with: Faker::Lorem.paragraph + find('#how_you_found_us_from-a-friend').click + fill_in 'member_how_you_found_us_other_reason', with: Faker::Lorem.paragraph, id: true uncheck 'newsletter'