1- import { useState , useEffect , useMemo } from 'react'
1+ import { useState , useEffect } from 'react'
22import {
33 X ,
44 ChevronLeft ,
88 MoreHorizontal ,
99} from 'lucide-react'
1010import { useNavigate , Link } from '@tanstack/react-router'
11- import { useQueryClient , useQuery } from '@tanstack/react-query'
11+ import { useQueryClient } from '@tanstack/react-query'
1212import type { StoryFeedItem , Story } from '@/entities/story/model/types'
1313import { useStoryViewer } from '../model/useStoryViewer'
1414import { STORY_VIEWER_UI } from './constants'
@@ -17,12 +17,12 @@ import ReportModal from '@/components/post/ReportModal'
1717import AccountInfoModal from '@/components/post/AccountInfoModal'
1818import { instance } from '@/shared/api/ky'
1919import { useCurrentUser } from '@/shared/auth/useCurrentUser'
20- import { getStoryDetail } from '@/entities/story/api/getStoryDetail'
2120import instagramLogo from '@/assets/instagram-black-logo.png'
2221
2322interface StoryViewerProps {
2423 feed : StoryFeedItem [ ]
2524 userId : string
25+ isDetailLoading ?: boolean
2626}
2727
2828const formatRelativeTime = ( createdAt : string ) => {
@@ -37,7 +37,11 @@ const formatRelativeTime = (createdAt: string) => {
3737 return `${ diffInHours } 시간 전`
3838}
3939
40- export function StoryViewer ( { feed, userId } : StoryViewerProps ) {
40+ export function StoryViewer ( {
41+ feed,
42+ userId,
43+ isDetailLoading,
44+ } : StoryViewerProps ) {
4145 const navigate = useNavigate ( )
4246 const queryClient = useQueryClient ( )
4347 const { data : me , isLoading : isMeLoading } = useCurrentUser ( )
@@ -48,19 +52,6 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
4852 const [ isAccountInfoOpen , setIsAccountInfoOpen ] = useState ( false )
4953 const [ isDeleteConfirmOpen , setIsDeleteConfirmOpen ] = useState ( false )
5054
51- const { data : detailData , isLoading : isDetailLoading } = useQuery ( {
52- queryKey : [ 'stories' , 'user' , userId ] ,
53- queryFn : ( ) => getStoryDetail ( userId ) ,
54- enabled : ! ! userId ,
55- } )
56-
57- const enrichedFeed = useMemo ( ( ) => {
58- if ( ! detailData ) return feed
59- return feed . map ( ( item ) =>
60- String ( item . userId ) === String ( userId ) ? detailData : item
61- )
62- } , [ feed , detailData , userId ] )
63-
6455 const {
6556 currentUser,
6657 currentStory,
@@ -71,7 +62,7 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
7162 handleNext,
7263 handlePrev,
7364 togglePause,
74- } = useStoryViewer ( enrichedFeed , userId )
65+ } = useStoryViewer ( feed , userId )
7566
7667 const isMine =
7768 ! isMeLoading &&
@@ -85,13 +76,7 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
8576 }
8677 } , [ imageError , isPaused , togglePause ] )
8778
88- if ( isDetailLoading || ! currentUser || ! currentStory ) {
89- return (
90- < div className = "fixed inset-0 z-[100] flex items-center justify-center bg-black" >
91- < div className = "h-8 w-8 animate-spin rounded-full border-4 border-gray-600 border-t-white" />
92- </ div >
93- )
94- }
79+ if ( ! currentUser ) return null
9580
9681 const isFirstStoryOfFirstUser =
9782 currentUserIndex === 0 && currentStoryIndex === 0
@@ -128,7 +113,7 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
128113 const handleDeleteStory = async ( ) => {
129114 try {
130115 const response = await instance
131- . delete ( `api/v1/stories/${ currentStory . id } ` )
116+ . delete ( `api/v1/stories/${ currentStory ? .id } ` )
132117 . json < { isSuccess : boolean ; code : string ; message : string } > ( )
133118 if ( response . isSuccess ) {
134119 queryClient . invalidateQueries ( { queryKey : [ 'stories' , 'feed' ] } )
@@ -173,6 +158,12 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
173158 ) }
174159
175160 < div className = { STORY_VIEWER_UI . STYLES . VIEWER_CARD } >
161+ { isDetailLoading && ! currentStory ?. imageUrl && (
162+ < div className = "absolute inset-0 z-10 flex items-center justify-center bg-black" >
163+ < div className = "h-8 w-8 animate-spin rounded-full border-4 border-gray-600 border-t-white" />
164+ </ div >
165+ ) }
166+
176167 < div className = { STORY_VIEWER_UI . STYLES . OVERLAY_TOP } >
177168 < div className = { STORY_VIEWER_UI . STYLES . PROGRESS_CONTAINER } >
178169 { currentUser . stories . map ( ( story : Story , i : number ) => (
@@ -208,9 +199,11 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
208199 />
209200 < div className = { STORY_VIEWER_UI . STYLES . USER_INFO } >
210201 < span className = "font-bold" > { currentUser . nickname } </ span >
211- < span className = "text-[13px] font-normal opacity-60" >
212- { formatRelativeTime ( currentStory . createdAt ) }
213- </ span >
202+ { currentStory && (
203+ < span className = "text-[13px] font-normal opacity-60" >
204+ { formatRelativeTime ( currentStory . createdAt ) }
205+ </ span >
206+ ) }
214207 </ div >
215208 </ Link >
216209
@@ -256,16 +249,18 @@ export function StoryViewer({ feed, userId }: StoryViewerProps) {
256249 </ div >
257250 ) : (
258251 < >
259- < img
260- key = { currentStory . imageUrl }
261- src = { currentStory . imageUrl }
262- className = "h-full w-full object-cover select-none"
263- alt = "story"
264- onError = { ( ) => setImageError ( true ) }
265- referrerPolicy = "no-referrer"
266- />
252+ { currentStory ?. imageUrl && (
253+ < img
254+ key = { currentStory . imageUrl }
255+ src = { currentStory . imageUrl }
256+ className = "h-full w-full object-cover select-none"
257+ alt = "story"
258+ onError = { ( ) => setImageError ( true ) }
259+ referrerPolicy = "no-referrer"
260+ />
261+ ) }
267262
268- { isMine && currentStory . viewCount !== undefined && (
263+ { isMine && currentStory ? .viewCount !== undefined && (
269264 < div className = "absolute bottom-4 left-4 z-50 flex flex-col items-start gap-1" >
270265 < span className = "text-[13px] font-semibold text-white drop-shadow-md" >
271266 { currentStory . viewCount } 명이 읽음
0 commit comments