Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: User flow redesign #736

Merged
merged 45 commits into from
Jun 2, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c7e1446
Implement new /tea_times page for listing current month's tea times
markbao May 18, 2018
b379470
Ensure user is redirected to the tea time they selected after signup/…
markbao May 18, 2018
b651599
After a user signs up for a tea time, set user's home city if blank
markbao May 18, 2018
a9ac3ba
Update tests for /tea_times to /tea_times/list move
markbao May 18, 2018
9fb02e6
Add tests for redirecting a user after signup and setting home city a…
markbao May 19, 2018
3fe8699
Add functionality and test for redirecting to a tea time after login
markbao May 19, 2018
f13d133
Deprecate cities: Cities -> Tea Times in menu/footer
markbao May 22, 2018
bb13080
Deprecate cities: user login redirect: cities -> tea times
markbao May 22, 2018
30f1595
Add /tea_times remind next month button, city select on signup
markbao May 23, 2018
e31d551
Allow /tea_times/123 page to be viewable publicly
markbao May 23, 2018
31f96ed
Fix attendance modal activation on pages navigated with Turbolinks
markbao May 23, 2018
b8bc48e
Remove type conversion for redirect URL after login
markbao May 23, 2018
e452572
new tea time page design
ankitshah811 May 30, 2018
257af98
new tea time event page partial complete
ankitshah811 Jun 1, 2018
f9802d8
fix broken tea_time reference in tea time row partial
ankitshah811 Jun 1, 2018
6810326
complete tea time event page
ankitshah811 Jun 1, 2018
46a94de
copy edit
ankitshah811 Jun 1, 2018
bc504b7
hide host commitment functionality, add edit profile clarity to accou…
ankitshah811 Jun 1, 2018
94d5e9a
turn off host profile creation email, make facebook field in host pro…
ankitshah811 Jun 1, 2018
ef719f9
new jump to city styles on tea time page
ankitshah811 Jun 1, 2018
c526389
jump to city copy edit
ankitshah811 Jun 1, 2018
387086e
raw text for TOS and privacy policy
ankitshah811 Jun 1, 2018
600cd9e
edit sign up home city dropdown styles
ankitshah811 Jun 1, 2018
865d1e5
Add Terms and Privacy template pages and links
markbao Jun 1, 2018
2850377
Tea Times: Add jump to city design and functionality
markbao Jun 1, 2018
53d0461
Tea Times: Remove modals
markbao Jun 1, 2018
696e40e
Tea Times: Don't show past tea times in this month
markbao Jun 1, 2018
a0be4e0
Redirect all city pages to /tea_times
markbao Jun 1, 2018
96b6ebd
Tea Times: Use city codes as anchor links
markbao Jun 1, 2018
c95dccd
Remove city page links
markbao Jun 1, 2018
9b01e04
Apply tea time display logic to host pages
markbao Jun 2, 2018
b2156ba
Fix city page test, now redirects
markbao Jun 2, 2018
bafffc6
jump cities styles
ankitshah811 Jun 2, 2018
5c3ce7b
jump city styles update
ankitshah811 Jun 2, 2018
bd7c300
add tagline to host profile partial
ankitshah811 Jun 2, 2018
8ce34d5
Tea Times: Sort page by cities with most tea times
markbao Jun 2, 2018
f881aa1
share links on tea time page, TOS and privacy policy
ankitshah811 Jun 2, 2018
58ff325
Merge branch 'mb/user-flow-redesign' of https://github.com/TeaWithStr…
ankitshah811 Jun 2, 2018
7bf355b
metadata for tea time event page
ankitshah811 Jun 2, 2018
fd1c1df
metadata for tea time index page
ankitshah811 Jun 2, 2018
390df30
Tea Times: Fix tea time ordering
markbao Jun 2, 2018
76b0d98
wrap tea time box in link
ankitshah811 Jun 2, 2018
d7fdb1c
modified status buttons on tea time index page
ankitshah811 Jun 2, 2018
739fa52
Merge branch 'mb/user-flow-redesign' of https://github.com/TeaWithStr…
ankitshah811 Jun 2, 2018
d5c7ce8
user behavior test copy fix
ankitshah811 Jun 2, 2018
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
10 changes: 9 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ def use_new_styles
go_back(exception)
end

# Override Devise's after_sign_in_path_for to check whether
# the user (here, `resource` would be User) has a stored
# redirect location, and use that as the path. Otherwise,
# go to a city page.
# See https://github.com/plataformatec/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update
def after_sign_in_path_for(resource)
if current_user.home_city.nil?
redirect_path = stored_location_for(resource)
if redirect_path
redirect_path
elsif current_user.home_city.nil?
cities_path
else
city_path(current_user.home_city)
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/attendance_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ def create
current_user.update_attributes(phone_number: params[:attendance][:phone_number])
end

# Save home city if they don't have one yet
if current_user.home_city.nil?
current_user.update_attributes(home_city: @tea_time.city)
end

if @attendance.save
# Send various emails (Should all be run async)
@attendance.send_confirmation_mail if @attendance.pending?
Expand Down
11 changes: 10 additions & 1 deletion app/controllers/registrations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@ def create
user_info = GetOrCreateNonWaitlistedUser.call(user_params)
if user_info[:new_user?] && user_info[:user].valid?
sign_in user_info[:user]
redirect_to cities_path

# Retrieve redirect location from Devise if exists
redirect_url = stored_location_for(User)

# Fall back to cities path if no redirect location exists
unless redirect_url
redirect_url = cities_path
end

redirect_to redirect_url
elsif !user_info[:new_user?] && user_info[:user].valid?
redirect_to new_user_session_path, alert: 'You\'ve made an account already. Log in using the same email. Click \'Forgot Password\' if you\'re confused.'
else
Expand Down
8 changes: 8 additions & 0 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ class SessionsController < Devise::SessionsController
def new
@use_new_styles = true
return redirect_to profile_path if current_user

# If the redirect_to_tt parameter exists, store the URL
# to redirect to after signup
# See https://github.com/plataformatec/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update
if params[:redirect_to_tt] && TeaTime.find(params[:redirect_to_tt])
store_location_for(:user, '/tea_times/' + params[:redirect_to_tt].to_i.to_s)
end

super
end
end
8 changes: 8 additions & 0 deletions app/controllers/static_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ def about
def jfdi_signup
@full_form = !request.xhr?
return redirect_to profile_path if current_user

# If the redirect_to_tt parameter exists, store the URL
# to redirect to after signup
# See https://github.com/plataformatec/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update
if params[:redirect_to_tt] && TeaTime.find(params[:redirect_to_tt])
store_location_for(:user, '/tea_times/' + params[:redirect_to_tt].to_i.to_s)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the param should be coerced to a string automatically when you concatenate it to the result of store_location_for - does it not work without the to_i.to_s that way?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this was a bit of a weird design decision. I was thinking that it was possible that params[:redirect_to_tt] might not be a string containing an integer, so here I was ensuring that it was an integer, but if we do TeaTime.find(params[:redirect_to_tt]) (which I added later) that already checks if it's an integer. I'll remove this.

end

if @full_form
render 'registrations/sign_up'
else
Expand Down
31 changes: 28 additions & 3 deletions app/controllers/tea_times_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
class TeaTimesController < ApplicationController
helper TeaTimesHelper
before_action :set_tea_time, except: [:index, :new, :create]
before_action :authenticate_user!
before_action :authorized?, only: [:new, :edit, :create, :update, :cancel, :destroy, :index]
before_action :set_tea_time, except: [:index, :list, :new, :create]
before_action :authenticate_user!, except: [:index]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/tea_times is accessible publicly now.

before_action :authorized?, only: [:new, :edit, :create, :update, :cancel, :destroy, :list]
before_action :use_new_styles, except: [:create, :update, :cancel, :destroy]

# GET /tea_times
# GET /tea_times.json
def index
@tea_times = TeaTime.this_month.order(start_time: :asc).includes(:city).all

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we are converting a list of tea times into a hash like:

{
  "San Francisco": [TeaTime, TeaTime, ...]
  "NYC": [TeaTime, TeaTime, ...]
}

along with a list of names in @cities.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return an array of TeaTime, not a hash. Additionally, this_month isn't a standard AR Scope and it's not defined on the TT model, so you'll need something like where(:created_at => Time.now.beginning_of_month..Time.now.end_of_month) instead I think. Might want to make the span a rolling 4 week period too so it doesn't weirdly cut over towards the end of a month?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickbarnwell

Re: array: Whoops, my bad for not being clear. I meant this comment to 'introduce' the following lines of code which are doing the process of converting that list to a hash.

Re: scope: I added a custom scope in the model, let me know if it looks right: https://github.com/TeaWithStrangers/tws-on-rails/pull/736/files#diff-c0448cf921e60c620dcf5c85c1718605R35

Re: rolling period: This was something Ankit requested in the spec - I think the idea was to have tea times come out in "batches" at the beginning of the month.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markbao @nickbarnwell

Re: rolling period — Mark is right on what I suggested in the spec. We discussed having following month's tea times be available with the click of a "Show Next Month's Tea Times" button. Not sure if we landed on a conclusion there. @markbao Do you remember?

# Array of cities holding tea times this month
# Extract all names of cities from tea times and deduplicate
@cities = @tea_times.map { |tt| tt.city.name }.uniq

# For each available city, create a hash entry and an empty list
# of tea times
@tea_times_by_city = Hash.new
@cities.each { |city| @tea_times_by_city[city] = [] }

# Iterate through tea times and segment into cities
@tea_times.each do |tt|
@tea_times_by_city[tt.city.name].push(tt)
end

respond_to do |format|
format.html { render layout: !request.xhr? }
format.json { render json: @tea_times }
end
end

# GET /tea_times/list
# GET /tea_times/list.json
def list
@tea_times = TeaTime.all
respond_to do |format|
format.html { render layout: !request.xhr? }
Expand Down
1 change: 1 addition & 0 deletions app/models/tea_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TeaTime < ActiveRecord::Base
scope :past, -> { before(Time.now.utc) }
scope :future, -> { after(Time.now.utc) }
scope :future_until, ->(until_time) { future.before(until_time) }
scope :this_month, -> { after(Date.today.at_beginning_of_month).before(Date.today.at_end_of_month) }

def date
start_time.strftime("%A, %D")
Expand Down
14 changes: 13 additions & 1 deletion app/views/shared/_tea_time_row.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,20 @@
</button>
<% end %>
<% end %>
<% elsif (no_signin_button ||= false) # No signin button; don't show signin CTA text %>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the /tea_times page with the new flow, we only want to display "Count Me In" and "Join Waitlist" buttons. We don't want to display "Sign in" buttons, so we have a special branch for the /tea_times page.

<%= link_to sign_up_path(redirect_to_tt: tea_time.id) do %>
<% if tea_time.spots_remaining? %>
<button class="spots<%= tea_time.spots_remaining %>">
Count Me In
</button>
<% else %>
<button class="yellow button">
Join Waitlist
</button>
<% end %>
<% end %>
<% else %>
<%= link_to new_user_session_path do %>
<%= link_to new_user_session_path(redirect_to_tt: tea_time.id) do %>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/signup page now accepts a ?redirect_to_tt=123 querystring parameter which is saved in the session as the tea time to redirect to.

<button class="yellow button">
Sign in to schedule
</button>
Expand Down
6 changes: 3 additions & 3 deletions app/views/static/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<span class='cover-photo-subtext'>
But you don’t discover that when you’re staring at a screen.
</span>
<%= link_to next_step_path, class: 'sign-up' do %>
<%= link_to tea_times_path, class: 'sign-up' do %>
<button class='orange cover-photo-cta'>
Let's Get Tea
</button>
Expand Down Expand Up @@ -70,7 +70,7 @@
<h1 class="small dark mid-page-cta">
Actually talk to people.
</h1>
<%= link_to next_step_path, class: 'sign-up' do %>
<%= link_to tea_times_path, class: 'sign-up' do %>
<button class='orange cover-photo-cta'>
Let's get tea
</button>
Expand Down Expand Up @@ -118,7 +118,7 @@
<h1 class="small dark mid-page-cta">
Do we get to high five yet?
</h1>
<%= link_to next_step_path, class: 'sign-up' do %>
<%= link_to tea_times_path, class: 'sign-up' do %>
<button class='orange cover-photo-cta'>
Yes
</button>
Expand Down
50 changes: 50 additions & 0 deletions app/views/tea_times/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<% next_month_name = Date.today.next_month.strftime("%B") %>

<div class="cover-photo" style="background-image: linear-gradient(to bottom, rgba(247, 191, 77, 0.87), rgba(247, 191, 77, 0.87)), url('<%= image_path("missing-city-image.jpg") %>'); margin-bottom: 50px;">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styles are inline because @ankitshah811 will do the CSS and I don't want to create classes that might be rewritten later.

<%= render partial: 'shared/header' %>
<div class="content">
<div class="content-box">
<h1 class="cover-photo-lede">Tea times this month</h1>
<span class='cover-photo-subtext'>
We announce tea times at the beginning of each month.
If nothing this month fits you, sign up and we'll
email you in <%= next_month_name %> about tea times
then.
</span>
</div>
</div>
</div>

<div class="container">
<div class="light-background">
<div>
<% if @tea_times_by_city.empty? %>
<p>
No tea times scheduled for this month! Check back later.
</p>
<% else %>
<p>
This month, there are tea times happening in <%= @cities.to_sentence %>.
</p>
<p>
If you don't live in any of these places or the tea times below don't
work for your schedule, we can try to make something work for you in
<%= next_month_name %>.
</p>
<% end %>
</div>
<div>
<button>Email me in <%= next_month_name %></button>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet implemented.

</div>
<% @tea_times_by_city.each do |city, tts| %>
<div class="tt-set-container">
<div class="tt-container tt-city-name" style="border: 5px solid #EF6236; color: #EF6236; font-weight: bold; height: 200px; padding: 20px; font-size: 30px; text-transform: uppercase; text-align: center;">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (Styles are inline because @ankitshah811 will do the CSS and I don't want to create classes that might be rewritten later.)

<%= city %>
</div>
<% tts.each do |tt| %>
<%= render partial: 'shared/tea_time_row', locals: {tea_time: tt, no_signin_button: true} %>
<% end %>
</div>
<% end %>
</div>
</div>
File renamed without changes.
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
end

resources :tea_times do
collection do
get 'list' => 'tea_times#list'
end
member do
post '/attendance' => 'attendance#create', as: :attendance
patch '/attendance/all' => 'attendance#mark', as: :mark
Expand Down
20 changes: 16 additions & 4 deletions spec/controllers/tea_times_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,39 @@
end

describe '#index' do
it 'should be viewable by all viewers' do
get :index
assert_response :success

sign_in @user
referer '/'
get :index
assert_response :success
end
end

describe '#list' do
context 'viewed by a host or admin' do
it 'should show *all* the tea times to hosts' do
sign_in @host
get :index
get :list
expect(assigns(:tea_times)).to eq(TeaTime.all)
end

it 'should show *all* the tea times to admins' do
sign_in @admin
get :index
get :list
expect(assigns(:tea_times)).to eq(TeaTime.all)
end
end

it 'should redirect normal and anonymous users to sign in' do
get :index
get :list
assert_response :redirect

sign_in @user
referer '/'
get :index
get :list
assert_response 302
end
end
Expand Down
42 changes: 42 additions & 0 deletions spec/features/user_behaviours_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@
expect(page).to have_content 'Dashboard'
end

scenario 'can sign up with a valid email and password and a redirect_to_tt path' do
tt = create(:tea_time)
visit sign_up_path(redirect_to_tt: tt.id)
fill_in('user_name', with: 'Darth Helmet')
fill_in('user_email', with: '[email protected]')
fill_in('user_password', with: SecureRandom.hex)
click_button("Let's Get Tea")
expect(page.current_path).to eq tea_time_path(tt.id)
end

scenario 'with blank name' do
sign_up_with('', '[email protected]')
#User should be redirected to the sign up page
Expand All @@ -23,6 +33,14 @@
expect(page).to have_content user.home_city.name
end

scenario 'can sign in with a redirect_to_tt path and be redirected correctly' do
tt = create(:tea_time)
user = create(:user)
visit new_user_session_path(redirect_to_tt: tt.id)
sign_in user
expect(page.current_path).to eq tea_time_path(tt.id)
end

scenario 'with an already created user account from a registration form' do
user = create(:user)
sign_up_with(user.nickname, user.email)
Expand Down Expand Up @@ -102,6 +120,30 @@
end
end

feature 'Registered User without home city' do
before(:each) do
@host = create(:user, :host)
@user = create(:user, home_city: nil)
@tt = create(:tea_time, host: @host, city: @host.home_city)
sign_in @user
end

feature 'Tea Time Attendance' do
scenario 'signing up to a tea time sets user home city to tea time city' do
visit city_path(@host.home_city)
expect(page.status_code).to eq(200)
click_link('Count Me In')
expect(current_path).to eq tea_time_path(@tt)

find('input.confirm').click

# Reload the user model and check the user's home city is set
@user.reload
expect(@user.home_city).to eq @tt.city
end
end
end

private
def sign_up_with(name, email, opts = nil)
visit sign_up_path
Expand Down