Skip to content

Commit

Permalink
Add up-down route
Browse files Browse the repository at this point in the history
  • Loading branch information
harsh-mn-yral committed Oct 18, 2023
1 parent a007beb commit b2a6a8b
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
import HotOrNotLayout from '$components/layout/HotOrNotLayout.svelte'
</script>

<svelte:head>
<title>Up Down | Hot or Not</title>
</svelte:head>

<HotOrNotLayout>
<svelte:fragment slot="content">
<slot />
</svelte:fragment>
</HotOrNotLayout>
25 changes: 25 additions & 0 deletions packages/web-client/src/routes/(feed)/(splash)/up-down/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const ssr = false

import type { PageLoad } from './$types'
import { redirect } from '@sveltejs/kit'
import { postCache } from '$lib/helpers/backend'

export const load: PageLoad = async ({ fetch }) => {
const res = await postCache(
fetch,
).get_top_posts_aggregated_from_canisters_on_this_network_for_hot_or_not_feed(
BigInt(0),
BigInt(1),
)

if ('Ok' in res && res.Ok[0]) {
throw redirect(
307,
`/up-down/${res.Ok[0].publisher_canister_id.toText()}@${
res.Ok[0].post_id
}`,
)
} else {
throw redirect(307, '/up-down/no-videos')
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
<script lang="ts">
import { beforeNavigate } from '$app/navigation'
import Button from '$components/button/Button.svelte'
import PlayerLayout from '$components/layout/PlayerLayout.svelte'
import HotOrNotVote from '$components/hot-or-not/HotOrNotVote.svelte'
import VideoPlayer from '$components/video/VideoPlayer.svelte'
import {
getHotOrNotPosts,
updatePostInWatchHistory,
type PostPopulated,
} from '$lib/helpers/feed'
import { updateURL } from '$lib/utils/feedUrl'
import Log from '$lib/utils/Log'
import { handleParams } from '$lib/utils/params'
import { joinArrayUniquely, updateMetadata } from '$lib/utils/video'
import { hotOrNotFeedVideos, playerState } from '$stores/playerState'
import { hideSplashScreen } from '$stores/popups'
import Hls from 'hls.js/dist/hls.min.js'
import { onMount, tick } from 'svelte'
import 'swiper/css'
import { Swiper, SwiperSlide } from 'swiper/svelte'
import type { PageData } from './$types'
import Icon from '$components/icon/Icon.svelte'
import UpDownVote from '$components/up-down/UpDownVote.svelte'
export let data: PageData
const fetchCount = 25
const fetchWhenVideosLeft = 10
const keepVideosLoadedCount: number = 3
let videos: PostPopulated[] = []
let currentVideoIndex = 0
let lastWatchedVideoIndex = -1
let noMoreVideos = false
let loading = false
let fetchedVideosCount = 0
let loadTimeout: ReturnType<typeof setTimeout> | undefined = undefined
let errorCount = 0
let showError = false
async function fetchNextVideos(force = false) {
// console.log(
// `to fetch: ${!noMoreVideos} && ${
// videos.length
// } - ${currentVideoIndex}<${fetchCount}, errorCount: ${errorCount}`
// );
if (
!noMoreVideos &&
(force || videos.length - currentVideoIndex < fetchWhenVideosLeft)
) {
try {
Log('info', 'Fetching videos for feed', {
res: 'fetching from ' + fetchedVideosCount,
source: 'hotOrNot.fetchNextVideos',
})
loading = true
const res = await getHotOrNotPosts(fetchedVideosCount, fetchCount)
if (res.error) {
if (errorCount < 4) {
loadTimeout = setTimeout(() => {
errorCount++
fetchNextVideos()
}, 5000)
} else {
clearTimeout(loadTimeout)
showError = true
loading = false
}
return
} else {
errorCount = 0
if (loadTimeout) clearTimeout(loadTimeout)
}
fetchedVideosCount = res.from
videos = joinArrayUniquely(videos, res.posts)
if (res.noMorePosts) {
noMoreVideos = res.noMorePosts
// const watchedVideos = await getWatchedVideosFromCache('watch-hon')
// videos = joinArrayUniquely(videos, watchedVideos)
} else if (!res.noMorePosts && res.posts.length < fetchCount - 10) {
fetchNextVideos(true)
}
await tick()
loading = false
Log('info', 'Fetched videos for feed', {
noMoreVideos,
source: 'hotOrNot.fetchNextVideos',
})
} catch (e) {
Log('error', 'Could not fetch videos for feed', {
error: e,
noMoreVideos,
source: 'hotOrNot.fetchNextVideos',
})
loading = false
}
}
}
async function handleChange(e: CustomEvent) {
lastWatchedVideoIndex = currentVideoIndex
const newIndex = e.detail[0].realIndex
currentVideoIndex = newIndex
fetchNextVideos()
updateURL(videos[currentVideoIndex])
updateMetadata(videos[currentVideoIndex])
}
async function handleUnavailableVideo(index: number) {
videos.splice(index, 1)
videos = videos
}
onMount(async () => {
updateURL()
$playerState.initialized = false
$playerState.muted = true
$playerState.visible = true
if (data?.post) {
videos = [data.post, ...videos]
updatePostInWatchHistory('watch-hon', data.post)
} else if ($hotOrNotFeedVideos.length) {
videos = $hotOrNotFeedVideos
$hotOrNotFeedVideos = []
}
await tick()
fetchNextVideos()
handleParams()
})
beforeNavigate(() => {
$playerState.visible = false
$playerState.muted = true
videos.length > 2 && hotOrNotFeedVideos.set(videos.slice(currentVideoIndex))
})
</script>

<svelte:head>
<title>Up Down | Hot or Not</title>
</svelte:head>

<Swiper
direction={'vertical'}
observer
cssMode
slidesPerView={1}
on:slideChange={handleChange}
spaceBetween={300}
class="h-full w-full">
{#each videos as post, i (i)}
<SwiperSlide
class="flex h-full w-full snap-always items-center justify-center">
{#if currentVideoIndex - 2 < i && currentVideoIndex + keepVideosLoadedCount > i}
<PlayerLayout
bind:post
index={i}
source="hon_feed"
watchHistoryDb="watch-hon"
showWalletLink
showReportButton
let:recordView
let:updateStats>
<VideoPlayer
on:watchComplete={updateStats}
on:loaded={() => hideSplashScreen(500)}
on:watchedPercentage={({ detail }) => recordView(detail)}
on:videoUnavailable={() => handleUnavailableVideo(i)}
index={i}
playFormat="hls"
{Hls}
inView={i == currentVideoIndex && $playerState.visible}
uid={post.video_uid} />

<svelte:fragment slot="hotOrNot">
<UpDownVote />
</svelte:fragment>
</PlayerLayout>
{/if}
</SwiperSlide>
{/each}
{#if showError}
<SwiperSlide class="flex h-full w-full items-center justify-center">
<div
class="relative flex h-full w-full flex-col items-center justify-center space-y-8 px-8">
<div class="text-center text-lg font-bold">
Error loading posts. Please, refresh the page.
</div>
<Button
type="primary"
on:click={(e) => e.preventDefault()}
href="/hotornot">
Clear here to refresh
</Button>
</div>
</SwiperSlide>
{/if}
{#if loading}
<SwiperSlide class="flex h-full w-full items-center justify-center">
<div
class="relative flex h-full w-full flex-col items-center justify-center space-y-8 px-8">
<div class="text-center text-lg font-bold">Loading</div>
</div>
</SwiperSlide>
{/if}
{#if noMoreVideos}
<SwiperSlide class="relative h-full w-full items-center justify-center">
<div
class="absolute flex h-full w-full flex-col items-center justify-center space-y-8 bg-black/50 px-8">
<Icon name="votes-graphics" class="w-56" />
<div class="text-center text-lg font-bold">
There are no more videos to vote on
</div>
<div class="absolute inset-x-0 bottom-20 z-[-1] max-h-48">
<HotOrNotVote disabled />
</div>
</div>
</SwiperSlide>
{/if}
</Swiper>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export const ssr = false
export const prerender = false

import { Principal } from '@dfinity/principal'
import type { PageLoad } from './$types'
import type { PostPopulated } from '$lib/helpers/feed'
import { individualUser } from '$lib/helpers/backend'
import Log from '$lib/utils/Log'

export const load: PageLoad = async ({ params, fetch }) => {
try {
const id = params.id.split('@')
const postId = BigInt(Number(id[1]))
const principal = Principal.from(id[0])
let cachedPost: PostPopulated | undefined = undefined

try {
const { idb } = await import('$lib/idb')
cachedPost = await idb.get('watch', params.id)
} catch (e) {
Log('error', 'Error while accessing IDB', {
error: e,
from: 'feedLoad',
type: 'idb',
})
cachedPost = undefined
}

if (cachedPost) {
return { post: cachedPost }
} else {
const r = await individualUser(
principal,
fetch,
).get_individual_post_details_by_id(postId)
if (r.video_uid) {
return {
post: {
...r,
publisher_canister_id: id[0],
created_by_user_principal_id:
r.created_by_user_principal_id.toText(),
post_id: postId,
score: BigInt(0),
} as PostPopulated,
}
} else {
return
}
}
} catch (e) {
return
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script lang="ts">
import HotOrNotVote from '$components/hot-or-not/HotOrNotVote.svelte'
import Icon from '$components/icon/Icon.svelte'
import { hideSplashScreen } from '$stores/popups'
import { onMount, tick } from 'svelte'
onMount(async () => {
await tick()
hideSplashScreen(500)
})
</script>

<div
class="absolute flex h-full w-full flex-col items-center justify-center space-y-8 bg-black/50 px-8">
<Icon name="votes-graphics" class="w-56" />
<div class="text-center text-lg font-bold">
There are no videos to vote on
</div>
<div class="absolute inset-x-0 bottom-20 z-[-1] max-h-48">
<HotOrNotVote disabled />
</div>
</div>
2 changes: 1 addition & 1 deletion packages/web-client/src/routes/(feed)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ $: pathname = $page.url.pathname
<slot />
</svelte:fragment>
<div class="w-full" slot="bottom-navigation">
{#if !pathname.includes('hotornot')}
{#if !pathname.includes('hotornot') && !pathname.includes('up-down')}
<BottomNavigation />
{/if}
</div>
Expand Down

0 comments on commit b2a6a8b

Please sign in to comment.