From 63c1dd197c121677b9acf51574b29bb01accf434 Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 22 Mar 2026 19:52:14 +0900 Subject: [PATCH] #297 --- .../theatre_comments_controller.rb | 2 +- .../spec/requests/theatre_comments_spec.rb | 14 ++-- backend/spec/requests/theatres_spec.rb | 22 ++++++- .../src/pages/theatres/TheatreDetailPage.tsx | 66 +++++++++---------- 4 files changed, 61 insertions(+), 43 deletions(-) diff --git a/backend/app/controllers/theatre_comments_controller.rb b/backend/app/controllers/theatre_comments_controller.rb index 0f31297..50ec9ef 100644 --- a/backend/app/controllers/theatre_comments_controller.rb +++ b/backend/app/controllers/theatre_comments_controller.rb @@ -6,7 +6,7 @@ class TheatreCommentsController < ApplicationController comments = TheatreComment .where(theatre_id: params[:theatre_id]) .where('no > ?', no_gt) - .order(:no) + .order(no: :desc) render json: comments.as_json(include: { user: { only: [:id, :name] } }) end diff --git a/backend/spec/requests/theatre_comments_spec.rb b/backend/spec/requests/theatre_comments_spec.rb index a9f04a0..856b309 100644 --- a/backend/spec/requests/theatre_comments_spec.rb +++ b/backend/spec/requests/theatre_comments_spec.rb @@ -51,14 +51,14 @@ RSpec.describe 'TheatreComments', type: :request do ) end - it 'theatre_id で絞り込み、no_gt より大きいものを no 昇順で返す' do + it 'theatre_id で絞り込み、no_gt より大きいものを no 降順で返す' do get "/theatres/#{theatre.id}/comments", params: { no_gt: 1 } expect(response).to have_http_status(:ok) - expect(response.parsed_body.map { |row| row['no'] }).to eq([2, 3]) + expect(response.parsed_body.map { |row| row['no'] }).to eq([3, 2]) expect(response.parsed_body.map { |row| row['content'] }).to eq([ - 'second comment', - 'third comment' + 'third comment', + 'second comment' ]) end @@ -68,8 +68,8 @@ RSpec.describe 'TheatreComments', type: :request do expect(response).to have_http_status(:ok) expect(response.parsed_body.first['user']).to eq({ - 'id' => bob.id, - 'name' => 'Bob' + 'id' => alice.id, + 'name' => 'Alice' }) expect(response.parsed_body.first['user'].keys).to contain_exactly('id', 'name') end @@ -78,7 +78,7 @@ RSpec.describe 'TheatreComments', type: :request do get "/theatres/#{theatre.id}/comments", params: { no_gt: -100 } expect(response).to have_http_status(:ok) - expect(response.parsed_body.map { |row| row['no'] }).to eq([1, 2, 3]) + expect(response.parsed_body.map { |row| row['no'] }).to eq([3, 2, 1]) end end diff --git a/backend/spec/requests/theatres_spec.rb b/backend/spec/requests/theatres_spec.rb index bee54f3..45a4b85 100644 --- a/backend/spec/requests/theatres_spec.rb +++ b/backend/spec/requests/theatres_spec.rb @@ -117,11 +117,18 @@ RSpec.describe 'Theatres API', type: :request do expect(theatre.host_user_id).to eq(member.id) expect(watch.expires_at).to be_within(1.second).of(30.seconds.from_now) - expect(json).to eq( + expect(json).to include( 'host_flg' => true, 'post_id' => nil, 'post_started_at' => nil ) + + expect(json.fetch('watching_users')).to contain_exactly( + { + 'id' => member.id, + 'name' => 'member user' + } + ) end end @@ -167,11 +174,22 @@ RSpec.describe 'Theatres API', type: :request do expect(response).to have_http_status(:ok) expect(theatre.reload.host_user_id).to eq(other_user.id) - expect(json).to eq( + expect(json).to include( 'host_flg' => false, 'post_id' => nil, 'post_started_at' => nil ) + + expect(json.fetch('watching_users')).to contain_exactly( + { + 'id' => member.id, + 'name' => 'member user' + }, + { + 'id' => other_user.id, + 'name' => 'other user' + } + ) end end diff --git a/frontend/src/pages/theatres/TheatreDetailPage.tsx b/frontend/src/pages/theatres/TheatreDetailPage.tsx index 3413a7b..ba8ec75 100644 --- a/frontend/src/pages/theatres/TheatreDetailPage.tsx +++ b/frontend/src/pages/theatres/TheatreDetailPage.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from 'react' import { Helmet } from 'react-helmet-async' import { useParams } from 'react-router-dom' +import ErrorScreen from '@/components/ErrorScreen' import PostEmbed from '@/components/PostEmbed' import PrefetchLink from '@/components/PrefetchLink' import TagDetailSidebar from '@/components/TagDetailSidebar' @@ -46,6 +47,7 @@ export default (() => { const [content, setContent] = useState ('') const [loading, setLoading] = useState (false) const [sending, setSending] = useState (false) + const [status, setStatus] = useState (200) const [theatre, setTheatre] = useState (null) const [theatreInfo, setTheatreInfo] = useState (INITIAL_THEATRE_INFO) const [post, setPost] = useState (null) @@ -60,7 +62,7 @@ export default (() => { }, [videoLength]) useEffect (() => { - lastCommentNoRef.current = comments.at (-1)?.no ?? 0 + lastCommentNoRef.current = comments[0]?.no ?? 0 }, [comments]) useEffect (() => { @@ -85,7 +87,7 @@ export default (() => { } catch (error) { - console.error (error) + setStatus ((error as any)?.response.status ?? 200) } }) () @@ -94,12 +96,6 @@ export default (() => { } }, [id]) - useEffect (() => { - commentsRef.current?.scrollTo ({ - top: commentsRef.current.scrollHeight, - behavior: 'smooth' }) - }, [comments]) - useEffect (() => { if (!(id)) return @@ -122,7 +118,7 @@ export default (() => { if (!(cancelled) && newComments.length > 0) { lastCommentNoRef.current = newComments[newComments.length - 1].no - setComments (prev => [...prev, ...newComments]) + setComments (prev => [...newComments, ...prev]) } const currentInfo = theatreInfoRef.current @@ -232,6 +228,9 @@ export default (() => { embedRef.current?.seek (targetTime) } + if (status >= 400) + return + return (
@@ -270,7 +269,7 @@ export default (() => {
{ e.preventDefault () @@ -282,28 +281,20 @@ export default (() => { setSending (true) await apiPost (`/theatres/${ id }/comments`, { content }) setContent ('') - commentsRef.current?.scrollTo ({ - top: commentsRef.current.scrollHeight, - behavior: 'smooth' }) + commentsRef.current?.scrollTo ({ top: 0, behavior: 'smooth' }) } finally { setSending (false) } }}> -
- 現在の同接数:{theatreInfo.watchingUsers.length} -
- -
-
    - {theatreInfo.watchingUsers.map (user => ( -
  • - {user.name || `名もなきニジラー(#${ user.id })`} -
  • ))} -
-
+ setContent (e.target.value)} + disabled={sending}/>
{
))} - - setContent (e.target.value)} - disabled={sending}/> + +
+
+ 現在の同接数:{theatreInfo.watchingUsers.length} +
+ +
+
    + {theatreInfo.watchingUsers.map (user => ( +
  • + {user.name || `名もなきニジラー(#${ user.id })`} +
  • ))} +
+
+