Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
609e6ca
user_icon コンポーネントを作成
sharoa119 May 27, 2025
da875a1
user_icon_listコンポーネントを作成
sharoa119 May 27, 2025
1afca2f
ダッシュボードに学習時間該当ユーザーのアイコンを表示する機能を実装
sharoa119 May 27, 2025
84e470f
学習時間該当ユーザーのアイコンに関するテストを追加
sharoa119 May 30, 2025
aa23aee
user_icon_list にデザインを適用、user_icon を partial に変更、テストファイル名もリネームに合わせて変更
machida Jun 27, 2025
3225480
コード整理とリファクタリング:定数化・スコープ追加・不要コード削除など
sharoa119 Aug 27, 2025
cc8eb03
ダッシュボードで全ユーザーに「現在学習中」アイコンが表示されるように修正
sharoa119 Aug 29, 2025
865bd8f
coderabbitai指摘対応: ユーザーアイコンリストのスクロール/レイアウト修正
sharoa119 Aug 29, 2025
fb9509e
TimeRangeHelperに対するテストを追加
sharoa119 Aug 29, 2025
35f583b
TimeRangeHelperで曜日をI18nから取得するように変更
sharoa119 Sep 8, 2025
0827fec
ユーザーアイコン表示での N+1 を解消
sharoa119 Sep 18, 2025
b1af698
LearningTimeFrameの曜日表示をI18n対応 & ダッシュボードカラム表示を修正
sharoa119 Sep 19, 2025
7737c90
指摘箇所を修正
sharoa119 Oct 2, 2025
9949f04
テスト用 LearningTimeFrames fixture を修正
sharoa119 Oct 27, 2025
b354863
main に合わせて schema.rb を更新(sad_streak → negative_streak の反映)
sharoa119 Nov 10, 2025
ec2a137
マイグレーション再実行に伴い schema.rb を更新
sharoa119 Nov 11, 2025
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
16 changes: 16 additions & 0 deletions app/components/users/current_user_icon_list_component.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.current-user-icon-list
.l-container
.current-user-icon-list__inner
h2.current-user-icon-list__title
span.current-user-icon-list__title-label
| 現在学習中
br
span.current-user-icon-list__title-time
= time_range(Time.zone.now)
ul.current-user-icon-list__items
- @users.each do |user|
li.current-user-icon-list__item
= render 'users/icon',
user: user,
link_class: 'current-users__item-link',
image_class: 'current-users__item-icon'
9 changes: 9 additions & 0 deletions app/components/users/current_user_icon_list_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class Users::CurrentUserIconListComponent < ViewComponent::Base
include TimeRangeHelper

def initialize(users:)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

他の場所はすべてinclude行とdefの間に1行開けているので合わせたほうがいいかもとおもいました。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ご指摘ありがとうございます!
確かにですね!修正いたしました!

@users = users
end
end
1 change: 1 addition & 0 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def display_dashboard
@calendar = NicoNicoCalendar.new(current_user, params[:niconico_calendar])
@target_end_date = GrassDateParameter.new(params[:end_date]).target_end_date
@times = Grass.times(current_user, @target_end_date)
@users_for_time_slot = User.currently_learning_except(current_user)
end

def display_events_on_dashboard
Expand Down
10 changes: 10 additions & 0 deletions app/helpers/time_range_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

module TimeRangeHelper
def time_range(time)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

コメントありがとうございます!
テスト追加いたします!!

start_hour = time.change(min: 0, sec: 0)
end_hour = start_hour + 1.hour

"(#{I18n.t('date.abbr_day_names')[time.wday]}) #{start_hour.strftime('%H:%M')} 〜 #{end_hour.strftime('%H:%M')}"
end
end
1 change: 1 addition & 0 deletions app/javascript/stylesheets/application.sass
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

@import application/blocks/course/courses

@import application/blocks/dashboard/current-user-icon-list
@import application/blocks/dashboard/dashboard-categories-item
@import application/blocks/dashboard/dashboard-contents
@import application/blocks/dashboard/welcome-message
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.current-user-icon-list
margin-bottom: 1rem
background-color: #eaeaf1
padding-block: .5rem
// fallback for older UA
padding-top: .5rem
padding-bottom: .5rem

.current-user-icon-list__inner
display: flex
align-items: center
gap: .5rem

.current-user-icon-list__items
display: flex
align-items: center
gap: .25rem
flex: 1 1 auto
min-width: 0
flex-wrap: nowrap
overflow-x: auto
scrollbar-gutter: stable both-edges

.current-user-icon-list__item
flex: 0 0 2.5rem
+media-breakpoint-up(md)
flex: 0 0 3rem
+media-breakpoint-down(sm)
flex: 0 0 2rem

.current-user-icon-list__title-label
+text-block(.875rem 1.4)
font-weight: 700
white-space: nowrap

.current-user-icon-list__title-time
+text-block(.75rem 1.4)
white-space: nowrap
8 changes: 8 additions & 0 deletions app/models/learning_time_frame.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ class LearningTimeFrame < ApplicationRecord
has_many :users, through: :learning_time_frames_users

validates :week_day, :activity_time, presence: true

scope :active_now, lambda {
now = Time.current
weekday = I18n.t('date.abbr_day_names')[now.wday]
hour = now.hour

where(week_day: weekday, activity_time: hour)
}
end
8 changes: 8 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,14 @@ class User < ApplicationRecord # rubocop:todo Metrics/ClassLength
:description
)

scope :currently_learning_except, lambda { |user|
students_and_trainees
.joins(:learning_time_frames)
.merge(LearningTimeFrame.active_now)
.where.not(id: user.id)
.with_attached_avatar
}

class << self
def notification_receiver(target)
case target
Expand Down
4 changes: 4 additions & 0 deletions app/views/home/index.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

.page-body.is-dash-board
.page-body__inner.has-side-nav

- if @users_for_time_slot.present?
= render Users::CurrentUserIconListComponent.new(users: @users_for_time_slot)

- if current_user.adviser?
= render 'adviser_dashboard'
- elsif current_user.mentor?
Expand Down
4 changes: 2 additions & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -957,8 +957,6 @@
t.text "mentor_memo"
t.text "after_graduation_hope"
t.date "training_ends_on"
t.boolean "negative_streak", default: false, null: false
t.integer "last_negative_report_id"
t.datetime "last_activity_at"
t.datetime "hibernated_at"
t.string "profile_name"
Expand All @@ -979,6 +977,8 @@
t.integer "career_path", default: 0, null: false
t.text "career_memo"
t.boolean "sent_student_before_auto_retire_mail", default: false
t.integer "last_negative_report_id"
t.boolean "negative_streak", default: false, null: false
t.datetime "training_completed_at"
t.index ["course_id"], name: "index_users_on_course_id"
t.index ["email"], name: "index_users_on_email", unique: true
Expand Down
42 changes: 42 additions & 0 deletions test/components/users/current_user_icon_list_component_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

require 'test_helper'

class CurrentUserIconListComponentTest < ViewComponent::TestCase
fixtures :users, :learning_time_frames

test 'shows user icons if multiple users have active learning time now' do
travel_to Time.zone.local(2025, 5, 28, 12, 0, 0) do
kimura = users(:kimura)
kensyu = users(:kensyu)

LearningTimeFramesUser.create!(user: kimura, learning_time_frame_id: 85)
LearningTimeFramesUser.create!(user: kensyu, learning_time_frame_id: 85)

users = User.students_and_trainees.joins(:learning_time_frames).merge(LearningTimeFrame.active_now)
assert_includes users, kimura
assert_includes users, kensyu
end
end

test 'excludes current user from the list even when they have active learning time' do
travel_to Time.zone.local(2025, 5, 28, 12, 0, 0) do
kimura = users(:kimura)
kensyu = users(:kensyu)
current_user = users(:hatsuno)

LearningTimeFramesUser.create!(user: kimura, learning_time_frame_id: 85)
LearningTimeFramesUser.create!(user: kensyu, learning_time_frame_id: 85)
LearningTimeFramesUser.create!(user: current_user, learning_time_frame_id: 85)

users_for_time_slot = User.students_and_trainees
.joins(:learning_time_frames)
.merge(LearningTimeFrame.active_now)
.where.not(id: current_user.id)

assert_includes users_for_time_slot, kimura
assert_includes users_for_time_slot, kensyu
assert_not_includes users_for_time_slot, current_user
end
end
end
12 changes: 6 additions & 6 deletions test/fixtures/learning_time_frames.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<% week_days = { '日' => 'sun', '月' => 'mon', '火' => 'tue', '水' => 'wed', '木' => 'thu', '金' => 'fri', '土' => 'sat' } %>
<% week_days.each_with_index do |(day_name, day_prefix), day_index| %>
<% (0..23).each_with_index do |hour, hour_index| %>
<%= "#{day_prefix}#{hour}:" %>
id: <%= day_index * 24 + hour_index + 1 %>
week_day: <%= day_name %>
activity_time: <%= hour %>
<% end %>
<% (0..23).each_with_index do |hour, hour_index| %>
<%= "#{day_prefix}#{hour}:" %>
id: <%= day_index * 24 + hour_index + 1 %>
week_day: <%= day_name %>
activity_time: <%= hour %>
<% end %>
<% end %>
20 changes: 20 additions & 0 deletions test/helpers/time_range_helper_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require 'test_helper'

class TimeRangeHelperTest < ActionView::TestCase
test 'formats weekday and time correctly' do
time = Time.zone.local(2025, 8, 29, 14, 30)
assert_equal '(金) 14:00 〜 15:00', time_range(time)
end

test 'formats exactly on the hour' do
time = Time.zone.local(2025, 8, 29, 10, 0)
assert_equal '(金) 10:00 〜 11:00', time_range(time)
end

test 'formats time crossing midnight' do
time = Time.zone.local(2025, 8, 31, 23, 59)
assert_equal '(日) 23:00 〜 00:00', time_range(time)
end
end