diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d3ea6a36467d74aa9c0801f3cfe01d6b3b763a7a..34df2b8292eba105f888989fb675e85fcc8e1b41 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -67,7 +67,10 @@ class UsersController < ApplicationController end def awarded_badges - @user_badges = @user.user_badges.joins(:badge) + @user_badges = @user.user_badges.includes(:badge) + .group_by { |ub| [ub.badge, ub.badge_type] } + .sort_by { |k, _| k[0].order(k[1]) } + render layout: 'without_sidebar' end def awarded_badge diff --git a/app/models/badge.rb b/app/models/badge.rb index 62a6127332294f0063388ff94602a1cc4a04942d..81b15d2c99df55aa83105673e578d5327f207771 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -1,4 +1,6 @@ class Badge < ApplicationRecord + BADGE_ORDER = %w[bronze silver gold default].freeze + has_many :user_badges, dependent: :destroy has_many :users, through: :user_badges @@ -9,4 +11,8 @@ class Badge < ApplicationRecord Badge.all.to_h { |b| [b.title, b.id] } end end + + def order(badge_type) + [display_order, BADGE_ORDER.index(badge_type)] + end end diff --git a/app/models/badges/badge_autobiographer.rb b/app/models/badges/badge_autobiographer.rb index c621b1692f6af6728f10283ad94f59f4ae581d25..091797f611e4baea587c142981f6603586df5470 100644 --- a/app/models/badges/badge_autobiographer.rb +++ b/app/models/badges/badge_autobiographer.rb @@ -43,7 +43,7 @@ class BadgeAutobiographer # @param [User] recv_user - The user who receives the badge def self.notify(new_badge, recv_user) content = "You have been awarded the badge '#{new_badge.badge.title}' - for updating your profile'" + for updating your profile" link = Rails.application.routes.path_for(controller: 'users', action: 'awarded_badges', id: recv_user.id) recv_user.create_notification(content, link) diff --git a/app/views/badges/_badge.html.erb b/app/views/badges/_badge.html.erb index 28391b17ece6e0b9cb46e4819a4070e0953b8f04..4dbd1460bcb59a93904cc654d4ecef4bf6c83e71 100644 --- a/app/views/badges/_badge.html.erb +++ b/app/views/badges/_badge.html.erb @@ -4,7 +4,7 @@ <% is_small ||= false %> -<span class="tooltip" id="<%= dom_id badge %>"> +<span style="white-space: nowrap;" class="tooltip" id="<%= dom_id badge %>"> <span class="user-badge <%= css_class if defined?(css_class) %>"> <% badge.icon.split(';').each do |icon| %> <i class="fas <%= icon %> <%= 'has-margin-right-1' unless is_small %>"></i> diff --git a/app/views/users/_tabs.html.erb b/app/views/users/_tabs.html.erb index 2046568ffe4c46c1722f40305e9864d7d58d7e65..72d8875b08e4e542819e39b06517ac1431ab7353 100644 --- a/app/views/users/_tabs.html.erb +++ b/app/views/users/_tabs.html.erb @@ -2,6 +2,9 @@ <%= link_to user_path(user), class: "tabs--item #{current_page?(user_path(user)) ? 'is-active' : ''}" do %> <i class="fas fa-user"></i> Profile <% end %> + <%= link_to user_awarded_badges_path(user), class: "tabs--item #{current_page?(user_awarded_badges_path(user)) ? 'is-active' : ''}" do %> + Awarded Badges + <% end %> <%= link_to user_activity_path(user), class: "tabs--item #{current_page?(user_activity_path(user)) ? 'is-active' : ''}" do %> Activity <% end %> @@ -18,9 +21,6 @@ <%= link_to user_preferences_path, class: "tabs--item #{current_page?(user_preferences_path) ? 'is-active' : ''}" do %> Preferences <% end %> - <%= link_to user_awarded_badges_path(user), class: "tabs--item #{current_page?(user_awarded_badges_path(user)) ? 'is-active' : ''}" do %> - Awarded Badges - <% end %> <%= link_to user_consent_path, class: "tabs--item #{current_page?(user_consent_path) ? 'is-active' : ''}" do %> Consent <% end %> diff --git a/app/views/users/awarded_badges.html.erb b/app/views/users/awarded_badges.html.erb index a2cb0f87e49b31ec48348ba3d2652d7248a0d433..adc409784cc4f7270742db3767971c48f952fe95 100644 --- a/app/views/users/awarded_badges.html.erb +++ b/app/views/users/awarded_badges.html.erb @@ -9,33 +9,62 @@ <div id="badges"> <table class="table is-full-width"> <tr> - <th>#</th> - <th>Display format</th> - <th>Badge description</th> + <th>Badge</th> + <th>Description</th> + <th>First awarded</th> <th>Reference Link</th> - <th>Pinned</th> + <% if @user == current_user %> + <th>Pinned</th> + <% end %> </tr> - <% @user_badges.each.with_index(1) do |el, index| %> + <%# [[badge, type, values] %> + <% @user_badges.each do |key, values| %> + <% badge = key[0] %> + <% badge_type = key[1] %> + <% first_ub = values.first %> <tr> - <td><%= index %></td> - <td style="min-width: 160px" id="<%= "badge-#{el.id}" %>"> - <%= render el.badge, css_class: "#{el.badge_type}-badge" %> + <td style="min-width: 160px; white-space: nowrap;" id="<%= "badge-#{badge.id}" %>"> + <% if values.count > 1 %> + <%= values.count %>x + <% end %> + <%= render badge, css_class: "#{badge_type}-badge" %> </td> - <td><%= el.badge.description %></td> + <td><%= badge.description %></td> <td> - <%= link_to el.badge_source.model_name.human, el.reference_url, class: 'button is-muted' %> + <span title="<%= first_ub.created_at.iso8601 %>"> + <%= time_ago_in_words(first_ub.created_at, locale: :en_abbrev) %> ago + </span> </td> <td> - <% if el.pinned %> - <span class="has-font-style-italic has-color-tertiary"> - Pinned - </span> + <% if values.count == 1 %> + <%= link_to first_ub.badge_source.model_name.human, first_ub.reference_url, class: 'button is-muted' %> <% else %> - <%= form_with :url => user_pin_badge_path(@user.id, el.id), method: :post do |form| %> - <%= form.submit "Pin", class: "button is-outlined" %> - <% end %> + <details> + <summary>...</summary> + <ol> + <% values.each do |ub| %> + <li> + <%= link_to ub.badge_source.model_name.human, ub.reference_url, class: 'button is-muted' %> + </li> + <% end %> + </ol> + </details> <% end %> </td> + <% if @user == current_user %> + <td> + <% if first_ub.pinned %> + <span class="has-font-style-italic has-color-tertiary"> + Pinned + </span> + <% else %> + <%= form_with :url => user_pin_badge_path(@user.id, first_ub.id), method: :post do |form| %> + <%= form.submit "Pin", class: "button is-outlined" %> + <% end %> + <% end %> + </td> + </tr> + <% end %> </tr> <% end %> </table> diff --git a/db/migrate/20231111110643_add_display_order_to_badges.rb b/db/migrate/20231111110643_add_display_order_to_badges.rb new file mode 100644 index 0000000000000000000000000000000000000000..cc263e2431c3e3c2aa3fe85176838bd093f58855 --- /dev/null +++ b/db/migrate/20231111110643_add_display_order_to_badges.rb @@ -0,0 +1,5 @@ +class AddDisplayOrderToBadges < ActiveRecord::Migration[7.0] + def change + add_column :badges, :display_order, :integer + end +end diff --git a/db/migrate/20231111113444_set_default_badge_display_order.rb b/db/migrate/20231111113444_set_default_badge_display_order.rb new file mode 100644 index 0000000000000000000000000000000000000000..70d01998b53b557502bb8f9d697e526c5e4dce0b --- /dev/null +++ b/db/migrate/20231111113444_set_default_badge_display_order.rb @@ -0,0 +1,17 @@ +class SetDefaultBadgeDisplayOrder < ActiveRecord::Migration[7.0] + def change + # Update existing badges to have a display order + Badge.find_by(title: BadgeAutobiographer.badge_name).update(display_order: 100) + Badge.find_by(title: BadgeFirstAnswer.badge_name).update(display_order: 200) + Badge.find_by(title: BadgeFirstQuestion.badge_name).update(display_order: 300) + Badge.find_by(title: BadgeTeacher.badge_name).update(display_order: 400) + Badge.find_by(title: BadgeSelfLearner.badge_name).update(display_order: 500) + Badge.find_by(title: BadgeFamousQuestion.badge_name).update(display_order: 600) + Badge.find_by(title: BadgeGreatAnswer.badge_name).update(display_order: 700) + Badge.find_by(title: BadgeGreatQuestion.badge_name).update(display_order: 800) + + if Badge.where(display_order: nil).any? + raise StandardError.new "There still seem to be badges with null display orders!" + end + end +end diff --git a/db/migrate/20231111113515_change_badges_display_order_to_not_null.rb b/db/migrate/20231111113515_change_badges_display_order_to_not_null.rb new file mode 100644 index 0000000000000000000000000000000000000000..2adffc04c6ea8dc2fb8e41f9ee72fedea3fd08f0 --- /dev/null +++ b/db/migrate/20231111113515_change_badges_display_order_to_not_null.rb @@ -0,0 +1,5 @@ +class ChangeBadgesDisplayOrderToNotNull < ActiveRecord::Migration[7.0] + def change + change_column_null :badges, :display_order, false + end +end diff --git a/db/schema.rb b/db/schema.rb index 69d3f835c3ae6bb303e16c1cfd7ac27ba08c8dd1..a346039fbf0905db92ec6a7970604325444f6cc5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_11_10_202034) do +ActiveRecord::Schema[7.0].define(version: 2023_11_11_113515) do create_table "abilities", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_id" t.string "name" @@ -99,6 +99,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_11_10_202034) do t.text "icon" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "display_order", null: false t.index ["title"], name: "index_badges_on_title", unique: true end diff --git a/db/seeds/badges.yml b/db/seeds/badges.yml index 2731d37ea3208e225deeb4b727a2e2c02974fe10..120507777381182bbc61bf9dede1bc5df72ecf5d 100644 --- a/db/seeds/badges.yml +++ b/db/seeds/badges.yml @@ -1,52 +1,39 @@ -# -#- name: Meta -# short_wiki: Discussions and feedback about the site itself in Q&A format. -# display_post_types: -# - <%= PostType['Question'].id %> -# post_type_ids: -# - <%= PostType['Question'].id %> -# - <%= PostType['Answer'].id %> -# tag_set_id: <%= TagSet.unscoped.where(name: 'Meta').first.id %> -# use_for_hot_posts: true -# use_for_advertisement: false -# color_code: bluegray -# license_id: <%= License.unscoped.first.id %> - -- title: <%= BadgeTeacher.badge_name %> - description: Help another community member with an good answer to their question. - icon: fa-chalkboard-teacher - -- title: <%= BadgeSelfLearner.badge_name %> - description: Answer your own question with an answer that others find useful. - icon: fa-graduation-cap +- title: <%= BadgeAutobiographer.badge_name %> + description: Complete your profile and upload a profile picture. + icon: fa-id-card + display_order: 100 - title: <%= BadgeFirstAnswer.badge_name %> description: Contribute your first answer. icon: fa-info-circle + display_order: 200 - title: <%= BadgeFirstQuestion.badge_name %> description: Ask your first question. icon: fa-question-circle + display_order: 300 + +- title: <%= BadgeTeacher.badge_name %> + description: Help another community member with an good answer to their question. + icon: fa-chalkboard-teacher + display_order: 400 + +- title: <%= BadgeSelfLearner.badge_name %> + description: Answer your own question with an answer that others find useful. + icon: fa-graduation-cap + display_order: 500 - title: <%= BadgeFamousQuestion.badge_name %> description: Ask a question that many others look at. icon: fa-eye;fa-star - -- title: <%= BadgeAutobiographer.badge_name %> - description: Complete your profile and upload a profile picture. - icon: fa-id-card - -- title: <%= BadgeGreatQuestion.badge_name %> - description: Ask a question that many others are also interested in. - icon: fa-retweet + display_order: 600 - title: <%= BadgeGreatAnswer.badge_name %> description: Help out the community by contributing a very helpful answer. icon: fa-hands-helping + display_order: 700 -# -#great_answer: -# title: Famous Answer -# description: This is a badge description -# icon: fa-test -# created_at: 2020-01-01T00:00:00.000000Z \ No newline at end of file +- title: <%= BadgeGreatQuestion.badge_name %> + description: Ask a question that many others are also interested in. + icon: fa-retweet + display_order: 800