Render Profile Fields on user profiles (#11485)

* Render left sidebar attributes on profile

* Display header profile fields

* Make changes to protect DEV data

* Don't render DEV header fields twice

* Wrap profile UI changes in a FeatureFlag

* Add spec to test mulitple display areas

* Use select over reject

Co-authored-by: Michael Kohl <me@citizen428.net>

* Move comment for documentation generators

* Update dev profile fields csv data

Co-authored-by: Michael Kohl <me@citizen428.net>
Co-authored-by: Ben Halpern <bendhalpern@gmail.com>
This commit is contained in:
Jacob Herrington 2020-12-09 09:41:11 -06:00 committed by GitHub
parent 8598ed090e
commit 692acd3cb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 210 additions and 81 deletions

View file

@ -234,6 +234,7 @@ class StoriesController < ApplicationController
# - Let's say it's `4`. On mobile it would display two rows: 1st with 3 badges and
# 2nd with 1 badge (!) <-- and that would look off.
@badges_limit = 6
@profile = @user.profile.decorate
set_surrogate_key_header "articles-user-#{@user.id}"
set_user_json_ld

View file

@ -0,0 +1,14 @@
class ProfileDecorator < ApplicationDecorator
DEV_HEADER_FIELDS = %w[employment_title employer_name].freeze
# Return a Hash of the profile fields that should be rendered for a given
# display area, e.g. :left_sidebar
def ui_attributes_for(area:)
names = ProfileField.public_send(area).pluck(:attribute_name)
# Temporary workaround: DEV specific header fields are hardcoded in the view
if SiteConfig.dev_to?
names -= DEV_HEADER_FIELDS
end
data.slice(*names).select { |_, v| v.present? }
end
end

View file

@ -16,6 +16,7 @@ class Profile < ApplicationRecord
brand_color2: :text_color_hex,
display_email_on_profile: :email_public,
display_looking_for_work_on_profile: :looking_for_work_publicly,
education: :education,
git_lab_url: :gitlab_url,
linked_in_url: :linkedin_url,
recruiters_can_contact_me_about_job_opportunities: :contact_consent,

View file

@ -1,34 +1,78 @@
<% if @user.employment_title.present? || (@user.looking_for_work_publicly == true && @user.looking_for_work == true) || @user.education.present? %>
<div class="profile-header__bottom fs-base">
<% if @user.education.present? %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Education</strong>
<p class="crayons-definition__value"><%= @user.education %></p>
</div>
<% end %>
<% if @user.employment_title.present? %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work</strong>
<p class="crayons-definition__value">
<%= @user.employment_title %>
<% if @user.employer_name.present? %>
<span class="opacity-50"> at </span>
<% if @user.employer_url.present? %>
<a href="<%= @user.employer_url %>" class="crayons-link crayons-link--brand" target="_blank" rel="noopener"><%= @user.employer_name %></a>
<% else %>
<%= @user.employer_name %>
<% end %>
<% if FeatureFlag.enabled?(:profile_admin) %>
<% if (header_fields = @profile.ui_attributes_for(area: :header)).present? %>
<div class="profile-header__bottom fs-base">
<% header_fields.each do |title, value| %>
<div class="crayons-definition">
<strong class="crayons-definition__title">
<%= sanitized_sidebar title.titleize %>
</strong>
<p class="crayons-definition__value">
<%= sanitized_sidebar value %>
</p>
</div>
<% end %>
<%# As we migrate to more generalized profiles, we don't want to break DEV %>
<% if SiteConfig.dev_to? %>
<% if @user.employment_title.present? || (@user.looking_for_work_publicly == true && @user.looking_for_work == true) %>
<% if @user.employment_title.present? %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work</strong>
<p class="crayons-definition__value">
<%= @user.employment_title %>
<% if @user.employer_name.present? %>
<span class="opacity-50"> at </span>
<% if @user.employer_url.present? %>
<a href="<%= @user.employer_url %>" class="crayons-link crayons-link--brand" target="_blank" rel="noopener"><%= @user.employer_name %></a>
<% else %>
<%= @user.employer_name %>
<% end %>
<% end %>
</p>
</div>
<% end %>
</p>
</div>
<% end %>
<% if @user.looking_for_work_publicly == true && @user.looking_for_work == true %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work status</strong>
<p class="crayons-definition__value">I'm looking for work!</p>
</div>
<% end %>
<% end %>
<% end %>
</div>
<% end %>
<% else %>
<% if @user.employment_title.present? || (@user.looking_for_work_publicly == true && @user.looking_for_work == true) || @user.education.present? %>
<div class="profile-header__bottom fs-base">
<% if @user.education.present? %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Education</strong>
<p class="crayons-definition__value"><%= @user.education %></p>
</div>
<% end %>
<% if @user.looking_for_work_publicly == true && @user.looking_for_work == true %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work status</strong>
<p class="crayons-definition__value">I'm looking for work!</p>
</div>
<% end %>
</div>
<% if @user.employment_title.present? %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work</strong>
<p class="crayons-definition__value">
<%= @user.employment_title %>
<% if @user.employer_name.present? %>
<span class="opacity-50"> at </span>
<% if @user.employer_url.present? %>
<a href="<%= @user.employer_url %>" class="crayons-link crayons-link--brand" target="_blank" rel="noopener"><%= @user.employer_name %></a>
<% else %>
<%= @user.employer_name %>
<% end %>
<% end %>
</p>
</div>
<% end %>
<% if @user.looking_for_work_publicly == true && @user.looking_for_work == true %>
<div class="crayons-definition">
<strong class="crayons-definition__title">Work status</strong>
<p class="crayons-definition__value">I'm looking for work!</p>
</div>
<% end %>
</div>
<% end %>
<% end %>

View file

View file

@ -32,52 +32,68 @@
<% end %>
<% cache "user-profile-sidebar-profile-details-#{@user.id}-#{@user.profile_updated_at}", expires_in: 10.days do %>
<% if @user.mostly_work_with.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Skills/languages</h3>
</header>
<% if FeatureFlag.enabled?(:profile_admin) %>
<% @profile.ui_attributes_for(area: :left_sidebar).each do |title, value| %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">
<%= sanitized_sidebar title.titleize %>
</h3>
</header>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.mostly_work_with %>
<div class="crayons-card__body">
<%= sanitized_sidebar value %>
</div>
</div>
</div>
<% end %>
<% end %>
<% else %>
<% if @user.mostly_work_with.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Skills/languages</h3>
</header>
<% if @user.currently_learning.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Learning/trying</h3>
</header>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.currently_learning %>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.mostly_work_with %>
</div>
</div>
</div>
<% end %>
<% end %>
<% if @user.currently_hacking_on.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Projects</h3>
</header>
<% if @user.currently_learning.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Learning/trying</h3>
</header>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.currently_hacking_on %>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.currently_learning %>
</div>
</div>
</div>
<% end %>
<% end %>
<% if @user.available_for.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Available for...</h3>
</header>
<% if @user.currently_hacking_on.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Projects</h3>
</header>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.available_for %>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.currently_hacking_on %>
</div>
</div>
</div>
<% end %>
<% if @user.available_for.present? %>
<div class="crayons-card crayons-card--secondary">
<header class="crayons-card__header">
<h3 class="crayons-subtitle-3">Available for...</h3>
</header>
<div class="crayons-card__body">
<%= sanitized_sidebar @user.available_for %>
</div>
</div>
<% end %>
<% end %>
<% end %>

View file

@ -91,7 +91,6 @@ end
##############################################################################
num_users = 10 * SEEDS_MULTIPLIER
users_in_random_order = seeder.create_if_none(User, num_users) do

View file

@ -1,18 +1,18 @@
Display email on profile,check_box,,,Basic,settings_only,false
Website URL,text_field,https://yoursite.com,,Basic,header,true
Summary,text_area,A short bio...,,Basic,header,true
Website URL,text_field,https://yoursite.com,,Basic,settings_only,true
Summary,text_area,A short bio...,,Basic,settings_only,true
Location,text_field,"Halifax, Nova Scotia",,Basic,header,true
Facebook URL,text_field,https://facebook.com/...,,Links,header,false
Youtube URL,text_field,https://www.youtube.com/channel/...,,Links,header,false
StackOverflow URL,text_field,https://stackoverflow.com/users/...,,Links,header,false
LinkedIn URL,text_field,https://www.linkedin.com/in/...,,Links,header,false
Behance URL,text_field,https://www.behance.net/...,,Links,header,false
Dribbble URL,text_field,https://dribbble.com/...,,Links,header,false
Medium URL,text_field,https://medium.com/@...,,Links,header,false
GitLab URL,text_field,https://gitlab.com/...,,Links,header,false
Instagram URL,text_field,https://www.instagram.com/...,,Links,header,false
Mastodon URL,text_field,https://...,,Links,header,false
Twitch URL,text_field,https://www.twitch.tv/...,,Links,header,false
Facebook URL,text_field,https://facebook.com/...,,Links,settings_only,false
Youtube URL,text_field,https://www.youtube.com/channel/...,,Links,settings_only,false
StackOverflow URL,text_field,https://stackoverflow.com/users/...,,Links,settings_only,false
LinkedIn URL,text_field,https://www.linkedin.com/in/...,,Links,settings_only,false
Behance URL,text_field,https://www.behance.net/...,,Links,settings_only,false
Dribbble URL,text_field,https://dribbble.com/...,,Links,settings_only,false
Medium URL,text_field,https://medium.com/@...,,Links,settings_only,false
GitLab URL,text_field,https://gitlab.com/...,,Links,settings_only,false
Instagram URL,text_field,https://www.instagram.com/...,,Links,settings_only,false
Mastodon URL,text_field,https://...,,Links,settings_only,false
Twitch URL,text_field,https://www.twitch.tv/...,,Links,settings_only,false
Education,text_field,,,Work,header,false
Employer name,text_field,Acme Inc.,,Work,header,false
Employer URL,text_field,https://dev.com,,Work,header,false

1 Display email on profile check_box Basic settings_only false
2 Website URL text_field https://yoursite.com Basic header settings_only true
3 Summary text_area A short bio... Basic header settings_only true
4 Location text_field Halifax, Nova Scotia Basic header true
5 Facebook URL text_field https://facebook.com/... Links header settings_only false
6 Youtube URL text_field https://www.youtube.com/channel/... Links header settings_only false
7 StackOverflow URL text_field https://stackoverflow.com/users/... Links header settings_only false
8 LinkedIn URL text_field https://www.linkedin.com/in/... Links header settings_only false
9 Behance URL text_field https://www.behance.net/... Links header settings_only false
10 Dribbble URL text_field https://dribbble.com/... Links header settings_only false
11 Medium URL text_field https://medium.com/@... Links header settings_only false
12 GitLab URL text_field https://gitlab.com/... Links header settings_only false
13 Instagram URL text_field https://www.instagram.com/... Links header settings_only false
14 Mastodon URL text_field https://... Links header settings_only false
15 Twitch URL text_field https://www.twitch.tv/... Links header settings_only false
16 Education text_field Work header false
17 Employer name text_field Acme Inc. Work header false
18 Employer URL text_field https://dev.com Work header false

View file

@ -2,6 +2,25 @@ require "rails_helper"
RSpec.describe "User edits their profile", type: :system do
let(:user) { create(:user) }
let!(:profile_field_group) { create(:profile_field_group, name: "Ice Cream") }
let!(:left_sidebar_profile_field) do
create(:profile_field,
profile_field_group: profile_field_group,
label: "Preferred Ice Cream Flavor",
display_area: "left_sidebar")
end
let!(:header_profile_field) do
create(:profile_field,
profile_field_group: profile_field_group,
label: "Hate Ice Cream Flavor",
display_area: "header")
end
let!(:settings_only_profile_field) do
create(:profile_field,
profile_field_group: profile_field_group,
label: "Imaginary Ice Cream Flavor",
display_area: "settings_only")
end
before do
sign_in user
@ -26,4 +45,39 @@ RSpec.describe "User edits their profile", type: :system do
expect(page).to have_css(".sticky")
end
end
describe "editing admin created profile fields" do
before do
allow(FeatureFlag).to receive(:enabled?).with(:profile_admin).and_return(true)
Profile.refresh_attributes!
end
it "renders profile fields" do
expect(page).to have_text(left_sidebar_profile_field.attribute_name.titleize)
expect(page).to have_text(header_profile_field.attribute_name.titleize)
expect(page).to have_text(settings_only_profile_field.attribute_name.titleize)
end
it "reflects set profile fields in the interface" do
fill_in "profile[#{left_sidebar_profile_field.attribute_name}]", with: "chocolate"
fill_in "profile[#{header_profile_field.attribute_name}]", with: "pistachio"
fill_in "profile[#{settings_only_profile_field.attribute_name}]", with: "cthulhu"
click_button "Save"
visit "/#{user.username}"
expect(page).not_to have_text(settings_only_profile_field.attribute_name.titleize)
expect(page).not_to have_text("cthulhu")
within(".crayons-layout__sidebar-left") do
expect(page).to have_text(left_sidebar_profile_field.attribute_name.titleize)
expect(page).to have_text("chocolate")
end
within(".profile-header") do
expect(page).to have_text(header_profile_field.attribute_name.titleize)
expect(page).to have_text("pistachio")
end
end
end
end