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
19 changes: 17 additions & 2 deletions src/features/story-viewer/model/useStoryViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import { useState, useCallback, useMemo, useEffect } from 'react'
import { useNavigate } from '@tanstack/react-router'
import type { StoryFeedItem } from '@/entities/story/model/types'

type UseStoryViewerOptions = {
onComplete?: () => void
}

export function useStoryViewer(
storiesData: StoryFeedItem[],
initialUserId: string
initialUserId: string,
options?: UseStoryViewerOptions
) {
const navigate = useNavigate()
const { onComplete } = options ?? {}
const STORY_DURATION = 5000
const INTERVAL_MS = 10

Expand Down Expand Up @@ -50,10 +56,19 @@ export function useStoryViewer(
to: '/stories/$user_id',
params: { user_id: String(nextUser.userId) },
})
} else if (onComplete) {
onComplete()
} else {
navigate({ to: '/', search: { page: 1 } })
}
}, [currentUser, state.storyIndex, currentUserIndex, storiesData, navigate])
}, [
currentUser,
state.storyIndex,
currentUserIndex,
storiesData,
navigate,
onComplete,
])

const handlePrev = useCallback(() => {
if (!currentUser) return
Expand Down
16 changes: 13 additions & 3 deletions src/features/story-viewer/ui/StoryViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ interface StoryViewerProps {
userId: string
detailUser?: StoryFeedItem
isDetailLoading?: boolean
onClose?: () => void
}

const formatRelativeTime = (createdAt: string) => {
Expand All @@ -43,8 +44,17 @@ export function StoryViewer({
userId,
detailUser,
isDetailLoading,
onClose,
}: StoryViewerProps) {
const navigate = useNavigate()

const handleClose = () => {
if (onClose) {
onClose()
} else {
navigate({ to: '/', search: { page: 1 } })
}
}
const queryClient = useQueryClient()
const { data: me, isLoading: isMeLoading } = useCurrentUser()

Expand All @@ -64,7 +74,7 @@ export function StoryViewer({
handleNext,
handlePrev,
togglePause,
} = useStoryViewer(feed, userId)
} = useStoryViewer(feed, userId, { onComplete: onClose })

const viewerUser =
detailUser && String(detailUser.userId) === String(userId)
Expand Down Expand Up @@ -125,7 +135,7 @@ export function StoryViewer({
if (response.isSuccess) {
queryClient.invalidateQueries({ queryKey: ['stories', 'feed'] })
queryClient.invalidateQueries({ queryKey: ['stories', 'user', userId] })
navigate({ to: '/', search: { page: 1 } })
handleClose()
}
} catch (error) {
console.error('스토리 삭제 실패:', error)
Expand All @@ -145,7 +155,7 @@ export function StoryViewer({
</div>

<button
onClick={() => navigate({ to: '/', search: { page: 1 } })}
onClick={handleClose}
className="absolute top-4 right-4 z-50 p-2 text-white transition-opacity hover:opacity-70"
>
<X className="h-9 w-9" strokeWidth={1.5} />
Expand Down
5 changes: 2 additions & 3 deletions src/features/story-viewer/ui/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ export const STORY_VIEWER_UI = {
OVERLAY_TOP:
'absolute top-0 z-30 flex w-full flex-col gap-3 bg-gradient-to-b from-black/60 to-transparent p-4 pb-10',
PROGRESS_CONTAINER: 'flex w-full gap-1',
PROGRESS_BAR: 'h-0.5 flex-1 overflow-hidden rounded-full bg-white/30',
PROGRESS_BAR_FILL:
'h-full bg-white transition-all duration-100 ease-linear',
PROGRESS_BAR: 'h-[3px] flex-1 overflow-hidden rounded-full bg-white/30',
PROGRESS_BAR_FILL: 'h-full bg-white',
HEADER: 'flex items-center justify-between',
USER_SECTION: 'flex items-center gap-3',
USER_INFO: 'flex items-center gap-2 text-[14px] font-medium text-white',
Expand Down
21 changes: 19 additions & 2 deletions src/routes/stories/$profile_name/$story_id.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
import { createFileRoute } from '@tanstack/react-router'
import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { StoryViewer } from '@/features/story-viewer/ui/StoryViewer'
import { useQuery } from '@tanstack/react-query'
import { getStoryDetail } from '@/entities/story/api/getStoryDetail'
import { useProfile } from '@/entities/user/model/hooks/useProfile'
import { useMemo } from 'react'
import { useCallback, useMemo } from 'react'
import type { StoryFeedItem } from '@/entities/story/model/types'
import { z } from 'zod'

const searchSchema = z.object({
returnTo: z.string().optional(),
})

export const Route = createFileRoute('/stories/$profile_name/$story_id')({
component: RouteComponent,
validateSearch: searchSchema,
})

function RouteComponent() {
const { profile_name: userId } = Route.useParams()
const { returnTo } = Route.useSearch()
const navigate = useNavigate()
const { data: profileData } = useProfile(Number(userId))

const handleClose = useCallback(() => {
if (returnTo) {
navigate({ to: returnTo })
} else {
navigate({ to: '/$userId', params: { userId } })
}
}, [navigate, returnTo, userId])

const { data: detailData, isLoading: isDetailLoading } = useQuery({
queryKey: ['stories', 'user', userId],
queryFn: () => getStoryDetail(userId),
Expand Down Expand Up @@ -51,6 +67,7 @@ function RouteComponent() {
userId={userId}
detailUser={userStoryFeedItem}
isDetailLoading={isDetailLoading}
onClose={handleClose}
/>
</div>
)
Expand Down
4 changes: 3 additions & 1 deletion src/widgets/profile-header/ui/ProfileAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link } from '@tanstack/react-router'
import { Link, useLocation } from '@tanstack/react-router'
import { cn } from '@/shared/lib/utils'
import { DefaultProfileImage } from '@/shared/ui/default-profile-image'

Expand All @@ -21,6 +21,7 @@ export function ProfileAvatar({
userId,
firstStoryId,
}: ProfileAvatarProps) {
const location = useLocation()
const avatarContent = avatarUrl ? (
<img
src={avatarUrl}
Expand Down Expand Up @@ -61,6 +62,7 @@ export function ProfileAvatar({
profile_name: String(userId),
story_id: String(firstStoryId),
}}
search={{ returnTo: location.pathname }}
>
{content}
</Link>
Expand Down