Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,65 @@
.card-header.is-sm
h2.card-header__title
| 学習連続記録
hr.a-border-tint
.card-body
.streak-container
.streak-item
.streak-item__content
.streak-item__label
| 現在の連続記録
.streak-item__days
.streak-item__number
= current_streak_days
.streak-item__unit
| 日
- if current_streak?
.streak-item__period
= current_streak_period
.streak-item
.streak-item__content
.streak-item__label
| 連続最高記録
.streak-item__days
.streak-item__number
= longest_streak_days
.streak-item__unit
| 日
- if longest_streak?
.streak-item__period
= longest_streak_period
- if target_user == helpers.current_user
.card-header__actions class="flex items-center gap-3"
label.a-form-help-link.is-danger(for='modal-study-streak')
span.a-form-help-link__label
| 学習連続記録とは?
span.a-help
i.fa-solid.fa-question
= form_with url: toggle_show_study_streak_user_path(target_user), method: :patch, local: true, html: { class: 'flex items-center' } do |f|
= hidden_field_tag :redirect_to, helpers.request.fullpath
label.a-on-off-checkbox.is-md
= check_box_tag :toggle, "1", target_user.show_study_streak,
class: "a-on-off-checkbox__input",
onchange: "this.form.submit()"
span
- if target_user.show_study_streak
hr.a-border-tint
.card-body
.streak-container
.streak-item
.streak-item__content
.streak-item__label
| 現在の連続記録
.streak-item__days
.streak-item__number
= current_streak_days
.streak-item__unit
| 日
- if current_streak?
.streak-item__period
= current_streak_period
.streak-item
.streak-item__content
.streak-item__label
| 連続最高記録
.streak-item__days
.streak-item__number
= longest_streak_days
.streak-item__unit
| 日
- if longest_streak?
.streak-item__period
= longest_streak_period
- if target_user
= render '/shared/modal', id: 'modal-study-streak', modal_title: '学習連続記録'
.modal__description.is-md
.a-short-text
p
| あなたのプロフィール・ダッシュボードに
| 連続で取り組んだ学習記録を表示する機能です。
br
| 日報の学習時間から何日連続で学習できたかを自動でカウントします。
| 記録が目に見えることで、日々の習慣化をサポートします。
p
= image_tag 'study_streak/about-study-streak.jpg',
alt: '学習連続記録の表示画面'
p
| 学習連続記録はプロフィールとダッシュボードに表示され、他のユーザーからも閲覧されます。
| 学習スタイルは人それぞれです。
| 休息日を設けている方やご自身のスケジュールに合わせて「週に数回じっくり取り組む」という方は
| オフにすることもできます。
br
| ※オフにしても、これまでの学習連続記録が消えることはありません。
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# frozen_string_literal: true

class StudyStreak::StudyStreakTrackerComponent < ViewComponent::Base
def initialize(study_streak:)
def initialize(study_streak:, target_user:)
@study_streak = study_streak
@target_user = target_user
end

def current_streak?
Expand Down Expand Up @@ -39,6 +40,8 @@ def longest_streak_period

private

attr_reader :target_user

def format_period(days:, start_on:, end_on:)
return '' if days.to_i.zero? || start_on.blank? || end_on.blank?

Expand Down
7 changes: 7 additions & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ def created
@role = params[:role] || 'student'
end

def toggle_show_study_streak
enabled = params[:toggle].present?
current_user.update!(show_study_streak: enabled)

redirect_to url_from(params[:redirect_to]) || root_path
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.

private

def fetch_target_users
Expand Down
2 changes: 2 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ class User < ApplicationRecord # rubocop:todo Metrics/ClassLength

validate :validate_uploaded_avatar_content_type

validates :show_study_streak, inclusion: { in: [true, false] }

validates :diploma_file, content_type: { in: ['application/pdf'], message: 'はPDF形式にしてください' }

validates :country_code, inclusion: { in: ISO3166::Country.codes }, allow_nil: true
Expand Down
2 changes: 1 addition & 1 deletion app/views/home/index.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
- if current_user.after_graduation_hope?
= render 'after_graduation_hope', user: current_user
- if current_user.total_learning_time.positive?
= render(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
= render(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: current_user))
- if current_user.student_or_trainee? && cookies[:user_grass] != current_user.id.to_s
= render(Grass::GrassComponent.new(user: current_user, times: @times, target_end_date: @target_end_date, path: :root_path))
- if current_user.github_account.present?
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
= render 'users/hibernation_history', user: @user
.col-xs-12(class="#{visible_learning_time_frames?(@user) ? 'col-lg-4 col-xxl-4' : 'col-lg-6 col-xxl-6'}")
- if @user.student_or_trainee? && @user.total_learning_time.positive?
= render(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
= render(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))
- unless @user.total_learning_time.zero? || @user.mentor?
= render(Grass::GrassComponent.new(user: @user, times: @times, target_end_date: @target_end_date, path: :user_path))
- if @user.student_or_trainee?
Expand Down
1 change: 1 addition & 0 deletions config/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ ja:
invoice_payment: 「請求書払い」
diploma_file: 卒業証書(PDF)
other_referral_source: FBCを知ったその他の経路
show_study_streak: 学習連続記録
discord_profile:
account_name: Discord アカウント
times_url: 分報URL
Expand Down
3 changes: 3 additions & 0 deletions config/routes/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
collection do
get :created
end
member do
patch :toggle_show_study_streak
end
resources :reports, only: %i(index), controller: "users/reports"
resources :comments, only: %i(index), controller: "users/comments"
resources :products, only: %i(index), controller: "users/products"
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20260323020435_add_show_study_streak_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddShowStudyStreakToUsers < ActiveRecord::Migration[8.1]
def change
add_column :users, :show_study_streak, :boolean, default: false, null: false
end
end
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,7 @@
t.boolean "sent_student_before_auto_retire_mail", default: false
t.boolean "sent_student_followup_message", default: false
t.boolean "show_mentor_profile", default: true, null: false
t.boolean "show_study_streak", default: false, null: false
t.string "subdivision_code"
t.string "subscription_id"
t.boolean "trainee", default: false, null: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
end

test 'renders current streak information' do
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))

# 現在の連続学習日数と期間を表示する
assert_selector '.streak-container'
Expand All @@ -38,7 +38,7 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
end

test 'renders longest streak information (ties resolved by most recent)' do
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))

# 最長連続日数も3日で、同率の場合は最新の期間を選ぶ
assert_selector '.streak-item__number', text: '3'
Expand All @@ -49,7 +49,7 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
user_without_learning = users(:hatsuno) # learning_times を含むレポートがないユーザー
reports = user_without_learning.reports_with_learning_times
study_streak = StudyStreak.new(reports, include_wip: false)
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak:))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak:, target_user: @user))

# 0日を表示し、期間テキストは表示しない
assert_selector '.streak-item__number', text: '0', count: 2
Expand All @@ -59,7 +59,7 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
end

test 'structure has required CSS classes' do
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))

assert_selector '.streak-container'
assert_selector '.streak-item', count: 2
Expand All @@ -70,14 +70,14 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
end

test 'date format follows "mm/dd 〜 mm/dd" pattern for the current year' do
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))

assert_selector '.streak-item__period', text: '08/20 〜 08/22'
end

test 'date format follows "yyyy/mm/dd 〜 yyyy/mm/dd" pattern for a past year' do
travel_to Time.zone.local(2025, 1, 1)
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak: @study_streak, target_user: @user))
assert_selector '.streak-item__period', text: '2024/08/20 〜 2024/08/22'
end

Expand All @@ -90,7 +90,7 @@ class StudyStreak::StudyStreakTrackerComponentTest < ViewComponent::TestCase
reports = user.reports_with_learning_times
study_streak = StudyStreak.new(reports)

render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak:))
render_inline(StudyStreak::StudyStreakTrackerComponent.new(study_streak:, target_user: user))
assert_selector '.streak-item__period', text: '2023/12/30 〜 2024/01/02'
end
end
2 changes: 2 additions & 0 deletions test/fixtures/users.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ machida:
profile_text: "株式会社ロッカのデザイナー。Ruby on Railsを使ったWebアプリを中心に多くのプロジェクトに参加。仙台で行われたRubyKaigi 2018のデザイン担当。フィヨルドブートキャンプでは主に HTML と CSS のレビュー担当。"
country_code: JP
subdivision_code: '13'
show_study_streak: true

adminonly: # adminのroleだけを持ったユーザー
login_name: adminonly
Expand Down Expand Up @@ -226,6 +227,7 @@ kimura:
mentor_memo: "kimuraさんのメモ"
country_code: JP
subdivision_code: '13'
show_study_streak: true

hatsuno:
login_name: hatsuno
Expand Down
30 changes: 29 additions & 1 deletion test/system/home_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class HomeTest < ApplicationSystemTestCase
assert_text '最新のみんなの日報'
end

test 'toggles_mentor_profile_visibility' do
test 'toggles mentor profile visibility' do
visit '/'
assert_text '駒形 真幸'
assert_text '株式会社ロッカの代表兼エンジニア。Rubyが大好きで怖話、フィヨルドブートキャンプなどを開発している。'
Expand All @@ -55,4 +55,32 @@ class HomeTest < ApplicationSystemTestCase
assert_no_text '株式会社ロッカの代表兼エンジニア。Rubyが大好きで怖話、フィヨルドブートキャンプなどを開発している。'
end
end

test 'toggles study streak visibility' do
user = users(:hajime)
visit_with_auth '/', 'hajime'

initial_show_study_streak = user.show_study_streak

assert_no_selector '.card-body', text: '現在の連続記録'
assert_no_selector '.card-body', text: '連続最高記録'
assert_not find('#toggle', visible: false).checked?
find('label.a-on-off-checkbox').click

assert_equal !initial_show_study_streak, user.reload.show_study_streak
assert_selector '.card-body', text: '現在の連続記録'
assert_selector '.card-body', text: '連続最高記録'
assert find('#toggle', visible: false).checked?
find('label.a-on-off-checkbox').click
end

test 'not show study streak toggle when no learning reports exist' do
assert_not users(:kensyu).reports_with_learning_times.present?
visit_with_auth '/', 'kensyu'
assert_no_selector 'label.a-on-off-checkbox'
logout
assert users(:hajime).reports_with_learning_times.present?
visit_with_auth '/', 'hajime'
assert_selector 'label.a-on-off-checkbox'
end
end
39 changes: 39 additions & 0 deletions test/system/users_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,43 @@ class UsersTest < ApplicationSystemTestCase
page.driver.browser.switch_to.alert.accept
assert_text "#{user.name} さんを削除しました。"
end

test 'toggles study streak visibility' do
user = users(:hajime)
visit_with_auth "/users/#{user.id}", 'hajime'

initial_show_study_streak = user.show_study_streak

assert_no_selector '.card-body', text: '現在の連続記録'
assert_no_selector '.card-body', text: '連続最高記録'
assert_not find('#toggle', visible: false).checked?
find('label.a-on-off-checkbox').click

assert_equal !initial_show_study_streak, user.reload.show_study_streak
assert_selector '.card-body', text: '現在の連続記録'
assert_selector '.card-body', text: '連続最高記録'
assert find('#toggle', visible: false).checked?
find('label.a-on-off-checkbox').click
end

test 'not show study streak toggle on other users profiles' do
user = users(:hajime)
visit_with_auth "/users/#{user.id}", 'kensyu'
assert_no_selector 'label.a-on-off-checkbox'
logout
visit_with_auth "/users/#{user.id}", 'hajime'
assert_selector 'label.a-on-off-checkbox'
end

test 'not show study streak toggle when no learning reports exist' do
user = users(:kensyu)
assert_not user.reports_with_learning_times.present?
visit_with_auth "/users/#{user.id}", 'kensyu'
assert_no_selector 'label.a-on-off-checkbox'
logout
user = users(:hajime)
assert user.reports_with_learning_times.present?
visit_with_auth "/users/#{user.id}", 'hajime'
assert_selector 'label.a-on-off-checkbox'
end
end
Loading