월별 랭킹 미세 조정 구현

ID: 654045ca-9016-4387-8f4f-c079e0e35bef

보통 완료

## 목표
랭킹 페이지 UI/UX 미세 조정: 월 선택, 뱃지 개선, 본인 하이라이트, 빈 상태

## 구현 내용

### 1. app/controllers/qt/sessions_controller.rb - rankings 액션 수정

현재 period="all"/"month" 기반 → month 파라미터 추가:

```ruby
def rankings
theme = @session.qt_theme
participant_user_ids = @session.qt_participants.pluck(:user_id)
users = User.where(id: participant_user_ids)

@period = params[:period] || "all"
@selected_month = params[:month] # "2026-03" 형식

@rankings = users.map do |user|
meditations = user.user_meditations.joins(:qt_content).where(qt_contents: { qt_theme_id: theme.id })

if @period == "month"
if @selected_month.present?
begin
date = Date.parse("#{@selected_month}-01")
meditations = meditations.where(meditation_date: date.beginning_of_month..date.end_of_month)
rescue Date::Error
meditations = meditations.where("user_meditations.meditation_date >= ?", Date.current.beginning_of_month)
end
else
meditations = meditations.where("user_meditations.meditation_date >= ?", Date.current.beginning_of_month)
end
end

completed = meditations.where.not(personal_meditation: [nil, ""])
shared = meditations.where(is_personal_meditation_shared: true)
tongtok = meditations.where(is_tongtok_completed: true)

{
user: user,
meditation_count: meditations.count,
completed_count: completed.count,
shared_count: shared.count,
tongtok_count: tongtok.count,
score: completed.count * 3 + shared.count * 2 + tongtok.count
}
end.sort_by { |r| -r[:score] }

# 월 선택을 위한 가용 월 목록 (세션 시작부터 현재까지)
@available_months = if @session.start_date.present?
start = @session.start_date.beginning_of_month
months = []
current = Date.current.beginning_of_month
while start <= current
months << current.strftime("%Y-%m")
current = current.prev_month.beginning_of_month
end
months
else
[Date.current.strftime("%Y-%m")]
end
end
```

### 2. app/views/qt/sessions/rankings.html.erb 전체 교체

```erb


<%# 헤더 %>

<%= link_to qt_session_path(@session), class: "text-text-secondary hover:text-text-primary transition-colors" do %>

<% end %>

<%= @session.title %> 랭킹


<%# 기간 필터 %>


<%= link_to "전체", rankings_qt_session_path(@session, period: "all"),
class: "px-4 py-2 text-small font-medium rounded-lg transition-colors #{@period == 'all' ? 'bg-brand-primary text-white' : 'bg-surface-subtle text-text-secondary hover:bg-gray-200 dark:hover:bg-gray-600'}" %>
<%= link_to "이번 달", rankings_qt_session_path(@session, period: "month"),
class: "px-4 py-2 text-small font-medium rounded-lg transition-colors #{@period == 'month' && @selected_month.blank? ? 'bg-brand-primary text-white' : 'bg-surface-subtle text-text-secondary hover:bg-gray-200 dark:hover:bg-gray-600'}" %>

<%# 월 선택 드롭다운 %>
<% if @available_months.size > 1 %>

월 선택
<% @available_months.each do |month| %>
<% month_label = Date.parse("#{month}-01").strftime("%Y년 %m월") %>
"
<%= "selected" if @selected_month == month %>>
<%= month_label %>

<% end %>

<% end %>

<%# 랭킹 목록 %>
<% if @rankings.empty? || @rankings.all? { |r| r[:score] == 0 } %>
<%= render "shared/empty_state",
title: "아직 랭킹 데이터가 없습니다",
description: "묵상을 완료하면 랭킹에 반영됩니다.",
action_text: "오늘의 묵상하기",
action_path: qt_today_path(session_id: @session.id) %>
<% else %>
<%= render "shared/card", padding: :md do %>


<% @rankings.each_with_index do |ranking, index| %>
<% rank = index + 1 %>
<% is_me = ranking[:user].id == current_user.id %>

<%# 순위 %>


<% if rank == 1 %>
🥇
<% elsif rank == 2 %>
🥈
<% elsif rank == 3 %>
🥉
<% else %>
<%= rank %>
<% end %>

<%# 아바타 + 이름 %>
<%= render "shared/avatar", name: ranking[:user].nickname, size: :sm %>



<%= ranking[:user].nickname %>
<% if is_me %>
<%= render "shared/badge", text: "나", variant: :info %>
<% end %>


묵상 <%= ranking[:completed_count] %>
공유 <%= ranking[:shared_count] %>
통독 <%= ranking[:tongtok_count] %>

<%# 점수 %>


<%= ranking[:score] %>




<% end %>

<% end %>

<%# 점수 계산 안내 %>
<%= render "shared/card", padding: :md do %>

점수 계산



묵상 완료 ×3
공유 ×2
통독 ×1

<% end %>
<% end %>

```

### 3. 핵심 변경 요약
1. **월 선택**: @available_months + select 드롭다운 (세션 시작월~현재)
2. **본인 하이라이트**: `is_me` 체크 → brand-primary/10 배경 + ring + "나" 뱃지
3. **다크모드 뱃지**: `dark:bg-amber-900/20` 추가
4. **빈 상태**: shared/empty_state 파셜 사용 (score 0인 경우도 포함)

### 4. 테스트 추가
test/controllers/qt/sessions_controller_test.rb에 추가:

```ruby
test "should get rankings with specific month" do
sign_in @daniel
get rankings_qt_session_path(@active_session, period: "month", month: Date.current.strftime("%Y-%m"))
assert_response :success
end
```

## 완료 기준
- [ ] 월 선택 드롭다운 동작
- [ ] 본인 순위 하이라이트 (배경색 + "나" 뱃지)
- [ ] 다크모드 대응 (amber, brand 배경)
- [ ] 빈 데이터 시 empty_state 파셜
- [ ] 기존 테스트 + 새 테스트 통과 (bin/rails test)

## 담당 파일
- app/controllers/qt/sessions_controller.rb (rankings 액션 수정)
- app/views/qt/sessions/rankings.html.erb (전체 교체)
- test/controllers/qt/sessions_controller_test.rb (테스트 추가)

첨부 이미지

이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)

JPEG, PNG, GIF, WebP / 최대 10MB

담당자: ranking-dev
생성일: 2026년 03월 03일 03:20

활동 로그

  • 팀리드 상태 변경: 할 일 → 완료

    2026년 03월 03일 03:23:37