Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(aih): implement next up from list retrieval for posts & ui #372

Merged
merged 2 commits into from
Jan 10, 2025
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
79 changes: 42 additions & 37 deletions apps/ai-hero/src/app/(content)/[post]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import Scrollycoding from '@/components/codehike/scrollycoding'
import { PlayerContainerSkeleton } from '@/components/player-skeleton'
import { PrimaryNewsletterCta } from '@/components/primary-newsletter-cta'
import { Share } from '@/components/share'
import Spinner from '@/components/spinner'
import { courseBuilderAdapter } from '@/db'
import type { List } from '@/lib/lists'
import { getListForPost } from '@/lib/lists-query'
import { type Post } from '@/lib/posts'
import { getAllPosts, getPost } from '@/lib/posts-query'
import { getPricingProps } from '@/lib/pricing-query'
Expand All @@ -25,7 +28,9 @@ import { compileMDX, MDXRemote } from 'next-mdx-remote/rsc'
import remarkGfm from 'remark-gfm'

import { Button } from '@coursebuilder/ui'
import { VideoPlayerOverlayProvider } from '@coursebuilder/ui/hooks/use-video-player-overlay'

import PostNextUpFromListPagination from '../_components/post-next-up-from-list-pagination'
import { PostPlayer } from '../posts/_components/post-player'
import { PostNewsletterCta } from '../posts/_components/post-video-subscribe-form'

Expand Down Expand Up @@ -141,6 +146,7 @@ export default async function PostPage(props: {
const searchParams = await props.searchParams
const params = await props.params
const post = await getPost(params.post)

const cookieStore = await cookies()
const ckSubscriber = cookieStore.has(CK_SUBSCRIBER_KEY)
const { allowPurchase, pricingDataLoader, product, commerceProps } =
Expand All @@ -156,6 +162,8 @@ export default async function PostPage(props: {
notFound()
}

const listLoader = getListForPost(post.id)

const squareGridPattern = generateGridPattern(
post.fields.title,
1000,
Expand All @@ -170,11 +178,10 @@ export default async function PostPage(props: {

return (
<main>
{hasVideo && <PlayerContainer post={post} />}
{hasVideo && <PlayerContainer listLoader={listLoader} post={post} />}
<div
className={cn('container relative max-w-screen-xl pb-16 sm:pb-24', {
'pt-16': !hasVideo,
// 'pb-24': ckSubscriber || hasVideo,
})}
>
<div
Expand All @@ -192,13 +199,7 @@ export default async function PostPage(props: {
aria-hidden="true"
/>
</div>
{/* <div className="absolute left-0 top-0 -z-10 h-[76px] w-full">
<img
src={squareGridPattern}
className="absolute left-0 top-0 h-[76px] w-full overflow-hidden object-cover object-top"
/>
<div className="from-background via-background/80 to-background absolute left-0 top-0 z-10 h-full w-full bg-gradient-to-r" />
</div> */}

<div className="relative z-10 flex w-full items-center justify-between">
<Link
href="/posts"
Expand All @@ -217,25 +218,19 @@ export default async function PostPage(props: {
<PostTitle post={post} />
<Contributor className="flex [&_img]:w-8" />
<Post post={post} />
<React.Suspense fallback={<Spinner />}>
<PostNextUpFromListPagination
postId={post.id}
listLoader={listLoader}
/>
</React.Suspense>
<div className="mx-auto mt-10 flex w-full max-w-sm flex-col gap-1">
<strong className="text-lg font-semibold">Share</strong>
<Share
className="bg-background w-full"
title={post?.fields.title}
/>
</div>
{/* <aside className="relative col-span-3 col-start-10 flex h-full flex-col pt-24">
<div className="top-20 md:sticky">
<Contributor className="hidden md:flex" />
<div className="mt-5 flex w-full flex-col gap-1">
<strong className="text-lg font-semibold">Share</strong>
<Share
className="bg-background w-full"
title={post?.fields.title}
/>
</div>
</div>
</aside> */}
</article>
</div>
</div>
Expand All @@ -262,7 +257,13 @@ export default async function PostPage(props: {
)
}

async function PlayerContainer({ post }: { post: Post | null }) {
async function PlayerContainer({
post,
listLoader,
}: {
post: Post | null
listLoader: Promise<List | null>
}) {
const displayOverlay = false

if (!post) {
Expand All @@ -276,21 +277,25 @@ async function PlayerContainer({ post }: { post: Post | null }) {
const ckSubscriber = cookieStore.has(CK_SUBSCRIBER_KEY)

return videoResource ? (
<Suspense
fallback={
<PlayerContainerSkeleton className="h-full max-h-[75vh] w-full bg-black" />
}
>
<section
aria-label="video"
className="mb-10 flex flex-col items-center justify-center border-b bg-black"
<VideoPlayerOverlayProvider>
<Suspense
fallback={
<PlayerContainerSkeleton className="h-full max-h-[75vh] w-full bg-black" />
}
>
<PostPlayer
className="aspect-video h-full max-h-[75vh] w-full overflow-hidden"
videoResource={videoResource}
/>
{!ckSubscriber && <PostNewsletterCta />}
</section>
</Suspense>
<section
aria-label="video"
className="mb-10 flex flex-col items-center justify-center border-b bg-black"
>
<PostPlayer
postId={post.id}
listLoader={listLoader}
className="aspect-video h-full max-h-[75vh] w-full overflow-hidden"
videoResource={videoResource}
/>
{!ckSubscriber && <PostNewsletterCta />}
</section>
</Suspense>
</VideoPlayerOverlayProvider>
) : resource ? null : null // spacer // <div className="pt-16" />
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'
import Link from 'next/link'
import { type List } from '@/lib/lists'
import { getNextUpResourceFromList } from '@/utils/get-nextup-resource-from-list'
import { ArrowRight, ChevronRight } from 'lucide-react'

import { Button } from '@coursebuilder/ui'

export default function PostNextUpFromListPagination({
listLoader,
postId,
}: {
listLoader: Promise<List | null>
postId: string
}) {
const list = React.use(listLoader)
const nextUp = list && getNextUpResourceFromList(list, postId)
return nextUp?.resource && nextUp?.resource?.fields?.state === 'published' ? (
<nav
className="mt-8 flex w-full flex-col items-center rounded bg-gray-950 px-5 py-10 text-center"
aria-label="List navigation"
>
<h2 className="fluid-2xl mb-3 font-semibold">Continue</h2>
<ul>
<li>
<Button
className="text-primary inline-flex items-center gap-2 text-lg lg:text-xl"
asChild
variant="link"
>
<Link href={`/${nextUp.resource.fields?.slug}`}>
{nextUp.resource.fields?.title} <ArrowRight className="w-4" />
</Link>
</Button>
</li>
</ul>
</nav>
) : null
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ export function CreateListForm() {
}

return (
<form onSubmit={handleSubmit} className="space-y-4">
<form
onSubmit={handleSubmit}
className="w-full max-w-md flex-shrink-0 space-y-4"
>
<h2 className="fluid-xl">Create New List</h2>
<div>
<Label htmlFor="title" className="mb-1 block text-sm font-medium">
Title
Expand All @@ -36,7 +40,7 @@ export function CreateListForm() {
id="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="block w-full rounded-md border border-gray-300 px-3 py-2"
// className="block w-full rounded-md border border-gray-300 px-3 py-2"
required
/>
</div>
Expand All @@ -48,7 +52,7 @@ export function CreateListForm() {
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
className="block w-full rounded-md border border-gray-300 px-3 py-2"
// className="block w-full rounded-md border border-gray-300 px-3 py-2"
rows={3}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function ListsTable({
return (
<>
{error && <Alert variant={'destructive'}>{error}</Alert>}
<Table>
<Table className="min-w-[600px] overflow-x-scroll">
<TableHeader>
<TableRow>
<TableHead>Title</TableHead>
Expand All @@ -49,12 +49,14 @@ export function ListsTable({
? `/lists/${list.fields.slug}/edit`
: `/lists/${list.fields.slug}`
}
className="text-primary hover:underline"
className="text-primary text-lg font-medium hover:underline"
>
{list.fields.title}
</Link>
</TableCell>
<TableCell>{list.fields.description}</TableCell>
<TableCell className="max-w-[90px] truncate">
{list.fields.description}
</TableCell>
<TableCell>{list.fields.type}</TableCell>
<TableCell>{list.resources?.length || 0}</TableCell>
<TableCell>
Expand Down
8 changes: 5 additions & 3 deletions apps/ai-hero/src/app/(content)/lists/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export default async function ListsPage() {
const canCreateContent = ability.can('create', 'Content')
return (
<div className="container flex flex-col gap-4 py-8">
<h1 className="text-2xl font-bold">Lists</h1>
<ListsTable canCreateContent={canCreateContent} lists={lists} />
{canCreateContent && <CreateListForm />}
<h1 className="fluid-2xl font-bold">Lists</h1>
<div className="flex flex-col gap-5 lg:flex-row">
<ListsTable canCreateContent={canCreateContent} lists={lists} />
{canCreateContent && <CreateListForm />}
</div>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react'
import { Suspense, use } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { PostPlayer } from '@/app/(content)/posts/_components/post-player'
import { SimplePostPlayer } from '@/app/(content)/posts/_components/post-player'
import Spinner from '@/components/spinner'
import { env } from '@/env.mjs'
import { useTranscript } from '@/hooks/use-transcript'
Expand Down Expand Up @@ -155,7 +155,7 @@ export const PostMetadataFormFields: React.FC<{
<>
{videoResource && videoResource.state === 'ready' ? (
<div className="-mt-5 border-b">
<PostPlayer videoResource={videoResource} />
<SimplePostPlayer videoResource={videoResource} />
<div className="flex items-center gap-1 px-4 pb-2">
<Button
variant="secondary"
Expand Down
Loading
Loading