diff --git a/packages/atlas/src/MainLayout.tsx b/packages/atlas/src/MainLayout.tsx
index 7e0e436dcf..c01db037dc 100644
--- a/packages/atlas/src/MainLayout.tsx
+++ b/packages/atlas/src/MainLayout.tsx
@@ -45,6 +45,21 @@ const LoadablePlaygroundLayout = loadable(
)
export const MainLayout: FC = () => {
+ return (
+ <>
+
+
+
+ } />
+ } />
+ } />
+ } />
+
+ >
+ )
+}
+
+const MiscUtils = () => {
useTimeMismatchWarning()
const scrollPosition = useRef(0)
const location = useLocation()
@@ -111,15 +126,5 @@ export const MainLayout: FC = () => {
}, parseInt(transitions.timings.routing) + ROUTING_ANIMATION_OFFSET)
}, [location, cachedLocation, locationState, navigationType, clearOverlays])
- return (
- <>
-
-
- } />
- } />
- } />
- } />
-
- >
- )
+ return null
}
diff --git a/packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx b/packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx
index 4e1e373f21..53ba388f29 100644
--- a/packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx
+++ b/packages/atlas/src/components/MinimizedPlayer/MinimizedPlayer.tsx
@@ -1,4 +1,4 @@
-import { forwardRef, useEffect, useState } from 'react'
+import { forwardRef, useEffect, useMemo, useState } from 'react'
import { VideoPlayer, VideoPlayerProps } from '@/components/_video/VideoPlayer'
import { useMediaMatch } from '@/hooks/useMediaMatch'
@@ -30,23 +30,26 @@ export const MinimizedPlayer = forwardRef(
const inView = isAllowed && mdMatch && !wasPausedOnTop ? isInView || forceExit || hasError : true
+ const actions = useMemo(
+ () => ({
+ onPause: () => {
+ setIsPaused(true)
+ videoPlayerProps.onPause?.()
+ },
+ onPlay: () => {
+ setIsPaused(false)
+ videoPlayerProps.onPlay?.()
+ },
+ onError: () => setHasError(true),
+ onMinimizedExit: () => setForceExit(true),
+ }),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [videoPlayerProps.onPlay, videoPlayerProps.onPause]
+ )
+
return (
- {
- setIsPaused(true)
- videoPlayerProps.onPause?.()
- }}
- onPlay={() => {
- setIsPaused(false)
- videoPlayerProps.onPlay?.()
- }}
- onError={() => setHasError(true)}
- onMinimizedExit={() => setForceExit(true)}
- {...videoPlayerProps}
- />
+
)
}
diff --git a/packages/atlas/src/components/_auth/LogInModal/LogInModal.tsx b/packages/atlas/src/components/_auth/LogInModal/LogInModal.tsx
index 0352e0df3f..ea952e841d 100644
--- a/packages/atlas/src/components/_auth/LogInModal/LogInModal.tsx
+++ b/packages/atlas/src/components/_auth/LogInModal/LogInModal.tsx
@@ -73,8 +73,8 @@ export const LogInModal = () => {
} catch (error) {
if (error.message === LogInErrors.ArtifactsNotFound) {
displaySnackbar({
- title: `We can't find ${atlasConfig.general.appName} membership associated with this email`,
- description: `Make sure that you are using the same email that you used to create your membership on ${atlasConfig.general.appName}.`,
+ title: `We can't find ${atlasConfig.general.appName} membership associated with these credentials`,
+ description: `Make sure that you are using the same email and password that you used to create your membership on ${atlasConfig.general.appName}.`,
iconType: 'error',
})
setError('email', { type: 'custom', message: 'Incorrect email or password.' })
diff --git a/packages/atlas/src/components/_video/VideoTile/VideoTile.tsx b/packages/atlas/src/components/_video/VideoTile/VideoTile.tsx
index e4e899651e..554b1dd059 100644
--- a/packages/atlas/src/components/_video/VideoTile/VideoTile.tsx
+++ b/packages/atlas/src/components/_video/VideoTile/VideoTile.tsx
@@ -1,6 +1,11 @@
+import styled from '@emotion/styled'
import { FC, memo, useState } from 'react'
import useResizeObserver from 'use-resize-observer'
+import { FlexBox } from '@/components/FlexBox'
+import { SkeletonLoader } from '@/components/_loaders/SkeletonLoader'
+import { square } from '@/styles'
+
import { VideoTileContainer } from './VideoTile.styles'
import { VideoThumbnail, VideoThumbnailProps } from '../VideoThumbnail'
@@ -62,6 +67,21 @@ export const VideoTile: FC = memo(
},
})
+ if (loadingDetails) {
+ return (
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
return (
= memo(
}
)
+const StyledThumbnailSkeleton = styled(SkeletonLoader)`
+ min-width: unset;
+ min-height: unset;
+ width: 100%;
+ aspect-ratio: 16/9;
+`
+
+const AvatarSkeleton = styled(SkeletonLoader)`
+ ${square(32)}
+`
+
VideoTile.displayName = 'VideoTile'
diff --git a/packages/atlas/src/components/_video/VideoTileViewer/VideoTileViewer.tsx b/packages/atlas/src/components/_video/VideoTileViewer/VideoTileViewer.tsx
index 1aac3b2d06..9baecaa309 100644
--- a/packages/atlas/src/components/_video/VideoTileViewer/VideoTileViewer.tsx
+++ b/packages/atlas/src/components/_video/VideoTileViewer/VideoTileViewer.tsx
@@ -1,4 +1,4 @@
-import { FC, useCallback } from 'react'
+import { FC, useCallback, useMemo } from 'react'
import { useNavigate } from 'react-router'
import { useBasicVideo } from '@/api/hooks/video'
@@ -44,17 +44,39 @@ export const VideoTileViewer: FC = ({
const channelHref = absoluteRoutes.viewer.channel(video?.channel.id)
- const handleCopyVideoURLClick = useCallback(() => {
- copyToClipboard(videoHref ? location.origin + videoHref : '', 'Video URL copied to clipboard')
- }, [videoHref, copyToClipboard])
+ const contextMenuItems = useMemo(
+ () => [
+ {
+ nodeStart: ,
+ onClick: () => copyToClipboard(videoHref ? location.origin + videoHref : '', 'Video URL copied to clipboard'),
+ label: 'Copy video URL',
+ },
+ ],
+ [copyToClipboard, videoHref]
+ )
+
+ const isNft = !!video?.nft
+ const slots = useMemo(
+ () => ({
+ bottomRight: {
+ element: video?.duration ? (
+
+ ) : null,
+ },
+ bottomLeft: isNft
+ ? {
+ element: ,
+ }
+ : undefined,
+ center: {
+ element: ,
+ type: 'hover',
+ } as const,
+ }),
+ [isNft, video?.duration]
+ )
- const contextMenuItems = [
- {
- nodeStart: ,
- onClick: handleCopyVideoURLClick,
- label: 'Copy video URL',
- },
- ]
+ const onAvatarClick = useCallback(() => navigate(channelHref), [channelHref, navigate])
return (
= ({
detailsVariant={detailsVariant}
videoHref={videoHref}
channelHref={channelHref}
- onChannelAvatarClick={() => navigate(channelHref)}
+ onChannelAvatarClick={onAvatarClick}
loadingDetails={loading || !video}
loadingThumbnail={isLoadingThumbnail}
thumbnailUrls={thumbnailPhotoUrls}
views={video?.viewsNum}
createdAt={video?.createdAt}
- slots={{
- bottomRight: {
- element: video?.duration ? (
-
- ) : null,
- },
- bottomLeft:
- video && video?.nft
- ? {
- element: ,
- }
- : undefined,
- center: {
- element: ,
- type: 'hover',
- },
- }}
+ slots={slots}
channelAvatarUrls={avatarPhotoUrls}
loadingAvatar={isLoadingAvatar}
channelTitle={video?.channel?.title}
diff --git a/packages/atlas/src/hooks/useGetAssetUrl.ts b/packages/atlas/src/hooks/useGetAssetUrl.ts
index 3be292c8b2..01d10bb77b 100644
--- a/packages/atlas/src/hooks/useGetAssetUrl.ts
+++ b/packages/atlas/src/hooks/useGetAssetUrl.ts
@@ -10,6 +10,7 @@ import { ConsoleLogger, DistributorEventEntry, SentryLogger, UserEventsLogger }
import { withTimeout } from '@/utils/misc'
const workingUrlMap = new Map()
+const assetsWithNoDistributions: string[] = []
export const getSingleAssetUrl = async (
urls: string[] | null | undefined,
@@ -18,7 +19,7 @@ export const getSingleAssetUrl = async (
timeout?: number,
opts?: AssetTestOptions
): Promise => {
- if (!urls || !urls.length) {
+ if (!urls || !urls.length || (id && assetsWithNoDistributions.includes(id))) {
return
}
@@ -90,6 +91,7 @@ export const getSingleAssetUrl = async (
urls,
error,
})
+ return undefined
})
})
}
@@ -108,9 +110,12 @@ export const useGetAssetUrl = (urls: string[] | undefined | null, type: AssetTyp
setUrl(undefined)
setIsLoading(true)
const resolvedUrl = await getSingleAssetUrl(urls, id, type, userBenchmarkTime.current ?? undefined, opts)
+
setIsLoading(false)
if (resolvedUrl) {
setUrl(resolvedUrl)
+ } else if (id) {
+ assetsWithNoDistributions.push(id)
}
}
diff --git a/packages/atlas/src/utils/getVideoCodec.ts b/packages/atlas/src/utils/getVideoCodec.ts
index 841fc45667..baad20587a 100644
--- a/packages/atlas/src/utils/getVideoCodec.ts
+++ b/packages/atlas/src/utils/getVideoCodec.ts
@@ -22,7 +22,7 @@ async function fetchPartialContent(url: string, range: { start: number; end: num
export const getVideoCodec = async (url: string): string => {
const fetchRange = { start: 0, end: 8192 }
- const arrayBuffer = await fetchPartialContent(url, fetchRange)
+ const arrayBuffer = await fetchPartialContent(url, fetchRange).catch(() => undefined)
if (arrayBuffer) {
try {
arrayBuffer.fileStart = 0
diff --git a/packages/atlas/src/views/viewer/HomeView.tsx b/packages/atlas/src/views/viewer/HomeView.tsx
index 54e2b05e11..7df0e55765 100644
--- a/packages/atlas/src/views/viewer/HomeView.tsx
+++ b/packages/atlas/src/views/viewer/HomeView.tsx
@@ -1,6 +1,5 @@
import styled from '@emotion/styled'
-import { FC, useEffect, useState } from 'react'
-import { useLocation } from 'react-router-dom'
+import { FC, useState } from 'react'
import { useGetCuratedHompageVideosQuery } from '@/api/queries/__generated__/videos.generated'
import { Section } from '@/components/Section/Section'
@@ -11,29 +10,15 @@ import { publicCryptoVideoFilter } from '@/config/contentFilter'
import { useBreakpointKey } from '@/hooks/useBreakpointKey'
import { useHeadTags } from '@/hooks/useHeadTags'
import { useVideoGridRows } from '@/hooks/useVideoGridRows'
-import { getCorrectLoginModal } from '@/providers/auth/auth.helpers'
-import { useAuthStore } from '@/providers/auth/auth.store'
import { DEFAULT_VIDEO_GRID, sizes } from '@/styles'
import { createPlaceholderData } from '@/utils/data'
import { InfiniteLoadingOffsets } from '@/utils/loading.contants'
export const HomeView: FC = () => {
const [hasMoreVideos, setHasMoreVideos] = useState(true)
- const location = useLocation()
- const {
- actions: { setAuthModalOpenName },
- } = useAuthStore()
-
const headTags = useHeadTags()
const { columns, fetchMore, tiles, loading, skipVideoIds } = useHomeVideos()
- useEffect(() => {
- if (location.state?.['redirectTo']) {
- setAuthModalOpenName(getCorrectLoginModal())
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [])
-
return (
diff --git a/packages/atlas/src/views/viewer/VideoView/VideoView.tsx b/packages/atlas/src/views/viewer/VideoView/VideoView.tsx
index 5a38268328..8e7234fff2 100644
--- a/packages/atlas/src/views/viewer/VideoView/VideoView.tsx
+++ b/packages/atlas/src/views/viewer/VideoView/VideoView.tsx
@@ -65,14 +65,8 @@ const DISABLE_VIEWS = true
export const VideoView: FC = () => {
const { id } = useParams()
- const { memberId, isLoggedIn } = useUser()
- const [showReportDialog, setShowReportDialog] = useState(false)
- const [reactionFee, setReactionFee] = useState()
const [availableTracks, setAvailableTracks] = useState([])
- const { openNftPutOnSale, openNftAcceptBid, openNftChangePrice, openNftPurchase, openNftSettlement, cancelNftSale } =
- useNftActions()
const { trackPageView } = useSegmentAnalytics()
- const reactionPopoverDismissed = usePersonalDataStore((state) => state.reactionPopoverDismissed)
const { loading, video, error } = useFullVideo(
id ?? '',
{
@@ -92,12 +86,7 @@ export const VideoView: FC = () => {
}
)
const [isInView, ref] = useIntersectionObserver()
- const [videoReactionProcessing, setVideoReactionProcessing] = useState(false)
const [isCommenting, setIsCommenting] = useState(false)
- const nftWidgetProps = useNftWidget(video)
- const { likeOrDislikeVideo } = useReactionTransactions()
- const { withdrawBid } = useNftTransactions()
- const { trackLikeAdded, trackDislikeAdded } = useSegmentAnalytics()
const [canPrefetchNew, setCanPrefetchNew] = useState(false)
const mdMatch = useMediaMatch('md')
@@ -107,10 +96,6 @@ export const VideoView: FC = () => {
cinematicView,
actions: { updateWatchedVideos },
} = usePersonalDataStore((state) => state)
- const videoCategory = video?.category ? video.category.id : null
- const belongsToCategories = videoCategory
- ? displayCategories.filter((category) => category.videoCategories.includes(videoCategory))
- : null
const { anyOverlaysOpen } = useOverlayManager()
const { ref: playerRef, inView: isPlayerInView } = useInView()
@@ -169,41 +154,23 @@ export const VideoView: FC = () => {
const [isShareDialogOpen, setShareDialogOpen] = useState(false)
+ const handleShare = useCallback(() => {
+ setShareDialogOpen(true)
+ }, [])
+
const savedVideoTimestamp = watchedVideos?.find((v) => v.id === video?.id)?.timestamp
const startTimestamp = useVideoStartTimestamp(video?.duration, savedVideoTimestamp)
const channelId = video?.channel?.id
- const channelName = video?.channel?.title
const videoId = video?.id
- const numberOfLikes = video?.reactions.filter(({ reaction }) => reaction === 'LIKE').length
- const numberOfDislikes = video?.reactions.filter(({ reaction }) => reaction === 'UNLIKE').length
const videoNotAvailable = !loading && !video
- const reactionStepperState = useMemo(() => {
- if (!video) {
- return 'loading'
- }
- if (videoReactionProcessing) {
- return 'processing'
- }
- const myReaction = video?.reactions.find(({ member: { id } }) => id === memberId)
- if (myReaction) {
- if (myReaction.reaction === 'LIKE') {
- return 'liked'
- }
- if (myReaction.reaction === 'UNLIKE') {
- return 'disliked'
- }
- }
- return 'default'
- }, [memberId, videoReactionProcessing, video])
-
// Save the video timestamp
// disabling eslint for this line since debounce is an external fn and eslint can't figure out its args, so it will complain.
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleTimeUpdate = useCallback(
throttle((time) => {
- if (!canPrefetchNew) {
+ if (!canPrefetchNew && time > 5_000) {
setCanPrefetchNew(true)
}
if (video?.id) {
@@ -220,40 +187,6 @@ export const VideoView: FC = () => {
}
}, [video?.id, handleTimeUpdate, updateWatchedVideos])
- const { getTxFee: getReactionFee } = useFee('reactToVideoTx')
-
- const handleCalculateFeeForPopover = async (reaction: VideoReaction) => {
- if (!memberId || !video?.id) return
- const fee = await getReactionFee([memberId, video?.id, reaction])
- setReactionFee(fee)
- }
-
- const handleReact = useCallback(
- async (reaction: VideoReaction) => {
- if (video?.id) {
- setVideoReactionProcessing(true)
- const fee = reactionFee || (await getReactionFee([memberId || '', video?.id, reaction]))
- const reacted = await likeOrDislikeVideo(video.id, reaction, video.title, fee)
- reaction === 'like'
- ? trackLikeAdded(video.id, memberId ?? 'no data')
- : trackDislikeAdded(video.id, memberId ?? 'no data')
- setVideoReactionProcessing(false)
- return reacted
- }
- return false
- },
- [
- getReactionFee,
- likeOrDislikeVideo,
- memberId,
- reactionFee,
- trackLikeAdded,
- trackDislikeAdded,
- video?.id,
- video?.title,
- ]
- )
-
// use Media Session API to provide rich metadata to the browser
useEffect(() => {
const supported = 'mediaSession' in navigator
@@ -277,10 +210,6 @@ export const VideoView: FC = () => {
}
}, [thumbnailUrls, video])
- const handleShare = () => {
- setShareDialogOpen(true)
- }
-
const handleAddVideoView = useCallback(() => {
if (!videoId || !channelId) {
return
@@ -299,7 +228,116 @@ export const VideoView: FC = () => {
}
const isCinematic = cinematicView || !mdMatch
- const sideItems = (
+ return (
+ <>
+ {headTags}
+
+
+
+
+ {videoNotAvailable ? (
+
+ ) : !loading && video ? (
+ setShareDialogOpen(false)}
+ onAddVideoView={handleAddVideoView}
+ isShareDialogOpen={isShareDialogOpen}
+ isVideoPending={!video?.media?.isAccepted}
+ videoId={video?.id}
+ autoplay
+ videoUrls={mediaUrls}
+ onEnd={handleVideoEnd}
+ onTimeUpdated={handleTimeUpdate}
+ startTime={startTimestamp}
+ isPlayNextDisabled={pausePlayNext}
+ ref={playerRef}
+ availableTextTracks={availableTracks}
+ />
+ ) : (
+
+ )}
+
+ {!isCinematic && (
+ <>
+ {!videoNotAvailable ? (
+
+ ) : mdMatch ? (
+
+ ) : null}
+ {!videoNotAvailable && (
+
+ )}
+ >
+ )}
+
+ {!isCinematic && }
+
+
+
+ {isCinematic && !(!mdMatch && videoNotAvailable) && (
+
+
+ {!videoNotAvailable ? (
+
+ ) : mdMatch ? (
+
+ ) : null}
+ {!videoNotAvailable && (
+
+ )}
+
+
+
+ )}
+
+ >
+ )
+}
+
+const SideItems = ({
+ video,
+ loading,
+ canStartPrefetch,
+}: {
+ video: ReturnType['video']
+ loading: boolean
+ canStartPrefetch: boolean
+}) => {
+ const { id } = useParams()
+ const { openNftPutOnSale, openNftAcceptBid, openNftChangePrice, openNftPurchase, openNftSettlement, cancelNftSale } =
+ useNftActions()
+ const channelId = video?.channel?.id
+ const channelName = video?.channel?.title
+ const videoNotAvailable = !loading && !video
+
+ const nftWidgetProps = useNftWidget(video)
+ const { withdrawBid } = useNftTransactions()
+
+ const mdMatch = useMediaMatch('md')
+ const { cinematicView } = usePersonalDataStore((state) => state)
+ const videoCategory = video?.category ? video.category.id : null
+ const belongsToCategories = videoCategory
+ ? displayCategories.filter((category) => category.videoCategories.includes(videoCategory))
+ : null
+ return (
{videoNotAvailable
? mdMatch && (
@@ -326,7 +364,7 @@ export const VideoView: FC = () => {
channelName={channelName}
videoId={id}
type="channel"
- shouldPrefetch={canPrefetchNew}
+ shouldPrefetch={canStartPrefetch}
/>
{belongsToCategories?.map((category) => (
{
))}
)
+}
+
+const DetailsItems = ({
+ video,
+ handleShare,
+}: {
+ video: ReturnType['video']
+ handleShare: () => void
+}) => {
+ const mdMatch = useMediaMatch('md')
+
+ const { memberId, isLoggedIn } = useUser()
+ const [showReportDialog, setShowReportDialog] = useState(false)
+ const [reactionFee, setReactionFee] = useState()
+ const reactionPopoverDismissed = usePersonalDataStore((state) => state.reactionPopoverDismissed)
+
+ const channelId = video?.channel?.id
+ const numberOfLikes = video?.reactions.filter(({ reaction }) => reaction === 'LIKE').length
+ const numberOfDislikes = video?.reactions.filter(({ reaction }) => reaction === 'UNLIKE').length
+ const videoCategory = video?.category ? video.category.id : null
+
+ const [videoReactionProcessing, setVideoReactionProcessing] = useState(false)
+ const { likeOrDislikeVideo } = useReactionTransactions()
+ const { trackLikeAdded, trackDislikeAdded } = useSegmentAnalytics()
+ const belongsToCategories = videoCategory
+ ? displayCategories.filter((category) => category.videoCategories.includes(videoCategory))
+ : null
+
+ const { getTxFee: getReactionFee } = useFee('reactToVideoTx')
+
+ const reactionStepperState = useMemo(() => {
+ if (!video) {
+ return 'loading'
+ }
+ if (videoReactionProcessing) {
+ return 'processing'
+ }
+ const myReaction = video?.reactions.find(({ member: { id } }) => id === memberId)
+ if (myReaction) {
+ if (myReaction.reaction === 'LIKE') {
+ return 'liked'
+ }
+ if (myReaction.reaction === 'UNLIKE') {
+ return 'disliked'
+ }
+ }
+ return 'default'
+ }, [memberId, videoReactionProcessing, video])
+
+ const handleCalculateFeeForPopover = async (reaction: VideoReaction) => {
+ if (!memberId || !video?.id) return
+ const fee = await getReactionFee([memberId, video?.id, reaction])
+ setReactionFee(fee)
+ }
+
+ const handleReact = useCallback(
+ async (reaction: VideoReaction) => {
+ if (video?.id) {
+ setVideoReactionProcessing(true)
+ const fee = reactionFee || (await getReactionFee([memberId || '', video?.id, reaction]))
+ const reacted = await likeOrDislikeVideo(video.id, reaction, video.title, fee)
+ reaction === 'like'
+ ? trackLikeAdded(video.id, memberId ?? 'no data')
+ : trackDislikeAdded(video.id, memberId ?? 'no data')
+ setVideoReactionProcessing(false)
+ return reacted
+ }
+ return false
+ },
+ [
+ getReactionFee,
+ likeOrDislikeVideo,
+ memberId,
+ reactionFee,
+ trackLikeAdded,
+ trackDislikeAdded,
+ video?.id,
+ video?.title,
+ ]
+ )
- const detailsItems = videoNotAvailable ? (
- mdMatch &&
- ) : (
+ return (
<>
{video ? (
@@ -416,81 +532,6 @@ export const VideoView: FC = () => {
>
)
-
- return (
- <>
- {headTags}
-
-
-
-
- {videoNotAvailable ? (
-
- ) : !loading && video ? (
- setShareDialogOpen(false)}
- onAddVideoView={handleAddVideoView}
- isShareDialogOpen={isShareDialogOpen}
- isVideoPending={!video?.media?.isAccepted}
- videoId={video?.id}
- autoplay
- videoUrls={mediaUrls}
- onEnd={handleVideoEnd}
- onTimeUpdated={handleTimeUpdate}
- startTime={startTimestamp}
- isPlayNextDisabled={pausePlayNext}
- ref={playerRef}
- availableTextTracks={availableTracks}
- />
- ) : (
-
- )}
-
- {!isCinematic && (
- <>
- {detailsItems}
- {!videoNotAvailable && (
-
- )}
- >
- )}
-
- {!isCinematic && sideItems}
-
-
-
- {isCinematic && !(!mdMatch && videoNotAvailable) && (
-
-
- {detailsItems}
- {!videoNotAvailable && (
-
- )}
-
- {sideItems}
-
- )}
-
- >
- )
}
const useIntersectionObserver = (options: IntersectionObserverInit = {}): [boolean, RefObject] => {
diff --git a/packages/atlas/src/views/viewer/ViewerLayout.tsx b/packages/atlas/src/views/viewer/ViewerLayout.tsx
index 60642fb089..4f6c0654d7 100644
--- a/packages/atlas/src/views/viewer/ViewerLayout.tsx
+++ b/packages/atlas/src/views/viewer/ViewerLayout.tsx
@@ -15,6 +15,8 @@ import { atlasConfig } from '@/config'
import { absoluteRoutes, relativeRoutes } from '@/config/routes'
import { useMediaMatch } from '@/hooks/useMediaMatch'
import { useSegmentAnalytics } from '@/hooks/useSegmentAnalytics'
+import { getCorrectLoginModal } from '@/providers/auth/auth.helpers'
+import { useAuthStore } from '@/providers/auth/auth.store'
import { useSearchStore } from '@/providers/search'
import { useUser } from '@/providers/user/user.hooks'
import { media, transitions } from '@/styles'
@@ -82,62 +84,11 @@ const locationToPageName = {
}
export const ViewerLayout: FC = () => {
- const location = useLocation()
- const locationState = location.state as RoutingState
const { isLoggedIn } = useUser()
- const [searchParams] = useSearchParams()
- const { trackPageView } = useSegmentAnalytics()
-
const navigate = useNavigate()
- const mdMatch = useMediaMatch('md')
- const searchOpen = useSearchStore((state) => state.searchOpen)
+ const location = useLocation()
+ const locationState = location.state as RoutingState
const displayedLocation = locationState?.overlaidLocation || location
- const afterGoogleRedirect = useRef(false)
-
- useEffect(() => {
- if (!location.pathname.includes('studio')) {
- const pageName =
- location.pathname === '/'
- ? 'Homepage'
- : Object.entries(locationToPageName).find(([key]) => location.pathname.includes(key))?.[1]
-
- //pages below will be tracked by the view components in order to include the additional params
- if (['Channel', 'Category', 'Video'].some((page) => pageName?.includes(page))) {
- return
- }
- const [query, referrerChannel, utmSource, utmCampaign, gState, gCode] = [
- searchParams.get('query'),
- searchParams.get('referrerId'),
- searchParams.get('utm_source'),
- searchParams.get('utm_campaign'),
- searchParams.get('state'),
- searchParams.get('code'),
- ]
- if (gState || gCode) {
- afterGoogleRedirect.current = true
- }
-
- // had to include this timeout to make sure the page title is updated
- const trackRequestTimeout = setTimeout(
- () =>
- trackPageView(pageName || 'Unknown page', {
- ...(location.pathname === absoluteRoutes.viewer.ypp()
- ? {
- referrerChannel: referrerChannel || undefined,
- utm_source: utmSource || undefined,
- utm_campaign: utmCampaign || undefined,
- }
- : {}),
- ...(location.pathname === absoluteRoutes.viewer.search() ? { searchQuery: query } : {}),
- }),
- 1000
- )
-
- return () => {
- clearTimeout(trackRequestTimeout)
- }
- }
- }, [location.pathname, searchParams, trackPageView])
return (
<>
@@ -204,7 +155,8 @@ export const ViewerLayout: FC = () => {
- {!mdMatch && !searchOpen && }
+
+
>
)
}
@@ -221,3 +173,76 @@ const MainContainer = styled.main`
: 'var(--size-topbar-height) var(--size-global-horizontal-padding) 0'};
}
`
+
+const BottomNavWrapper = () => {
+ const searchOpen = useSearchStore((state) => state.searchOpen)
+ const mdMatch = useMediaMatch('md')
+ if (!mdMatch && !searchOpen) {
+ return
+ }
+ return null
+}
+
+const MiscUtils = () => {
+ const location = useLocation()
+ const [searchParams] = useSearchParams()
+ const { trackPageView } = useSegmentAnalytics()
+ const {
+ actions: { setAuthModalOpenName },
+ } = useAuthStore()
+ const afterGoogleRedirect = useRef(false)
+
+ useEffect(() => {
+ if (location.state?.['redirectTo']) {
+ setAuthModalOpenName(getCorrectLoginModal())
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ useEffect(() => {
+ if (!location.pathname.includes('studio')) {
+ const pageName =
+ location.pathname === '/'
+ ? 'Homepage'
+ : Object.entries(locationToPageName).find(([key]) => location.pathname.includes(key))?.[1]
+
+ //pages below will be tracked by the view components in order to include the additional params
+ if (['Channel', 'Category', 'Video'].some((page) => pageName?.includes(page))) {
+ return
+ }
+ const [query, referrerChannel, utmSource, utmCampaign, gState, gCode] = [
+ searchParams.get('query'),
+ searchParams.get('referrerId'),
+ searchParams.get('utm_source'),
+ searchParams.get('utm_campaign'),
+ searchParams.get('state'),
+ searchParams.get('code'),
+ ]
+ if (gState || gCode) {
+ afterGoogleRedirect.current = true
+ }
+
+ // had to include this timeout to make sure the page title is updated
+ const trackRequestTimeout = setTimeout(
+ () =>
+ trackPageView(pageName || 'Unknown page', {
+ ...(location.pathname === absoluteRoutes.viewer.ypp()
+ ? {
+ referrerChannel: referrerChannel || undefined,
+ utm_source: utmSource || undefined,
+ utm_campaign: utmCampaign || undefined,
+ }
+ : {}),
+ ...(location.pathname === absoluteRoutes.viewer.search() ? { searchQuery: query } : {}),
+ }),
+ 1000
+ )
+
+ return () => {
+ clearTimeout(trackRequestTimeout)
+ }
+ }
+ }, [location.pathname, searchParams, trackPageView])
+
+ return null
+}