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:
parent
8598ed090e
commit
692acd3cb2
9 changed files with 210 additions and 81 deletions
|
|
@ -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
|
||||
|
|
|
|||
14
app/decorators/profile_decorator.rb
Normal file
14
app/decorators/profile_decorator.rb
Normal 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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 %>
|
||||
|
|
|
|||
0
app/views/users/_profile_fields.html.erb
Normal file
0
app/views/users/_profile_fields.html.erb
Normal 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 %>
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ end
|
|||
|
||||
##############################################################################
|
||||
|
||||
|
||||
num_users = 10 * SEEDS_MULTIPLIER
|
||||
|
||||
users_in_random_order = seeder.create_if_none(User, num_users) do
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue