feat: enhance endpoint responses with pagination, fixes #163
This commit is contained in:
parent
642e5df20a
commit
2b7e6db146
|
@ -5,6 +5,7 @@ import { Hero } from '../../components/Hero'
|
|||
import { PostsGrid } from '../../components/PostsGrid'
|
||||
import { uiConfigs } from '../../configs/ui.configs'
|
||||
import { useRecentPosts } from '../../queries/useRecentPosts.query'
|
||||
import { ApiPaginatedPayload } from '../../types/data.types'
|
||||
import { LPE } from '../../types/lpe.types'
|
||||
import { lsdUtils } from '../../utils/lsd.utils'
|
||||
import { PodcastShowsPreview } from '../PodcastShowsPreview'
|
||||
|
@ -16,14 +17,14 @@ export type HomePageProps = React.DetailedHTMLProps<
|
|||
data: {
|
||||
tags: string[]
|
||||
shows: LPE.Podcast.Show[]
|
||||
latest: LPE.Post.Document[]
|
||||
latest: ApiPaginatedPayload<LPE.Post.Document[]>
|
||||
highlighted: LPE.Post.Document[]
|
||||
}
|
||||
}
|
||||
|
||||
export const HomePage: React.FC<HomePageProps> = ({
|
||||
data,
|
||||
data: { highlighted = [], shows = [], tags = [], latest = [] },
|
||||
data: { highlighted = [], shows = [], tags = [], latest },
|
||||
...props
|
||||
}) => {
|
||||
const query = useRecentPosts({ initialData: latest, limit: 10 })
|
||||
|
|
|
@ -5,12 +5,13 @@ import PodcastShowCard from '@/components/Podcasts/PodcastShowCard'
|
|||
import { Button, Typography } from '@acid-info/lsd-react'
|
||||
import styled from '@emotion/styled'
|
||||
import { useRecentEpisodes } from '../queries/useRecentEpisodes.query'
|
||||
import { ApiPaginatedPayload } from '../types/data.types'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
import { lsdUtils } from '../utils/lsd.utils'
|
||||
|
||||
interface Props {
|
||||
show: LPE.Podcast.Show
|
||||
latestEpisodes: LPE.Podcast.Document[]
|
||||
latestEpisodes: ApiPaginatedPayload<LPE.Podcast.Document[]>
|
||||
highlightedEpisodes: LPE.Podcast.Document[]
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Page.getLayout = function getLayout(page: React.ReactNode) {
|
|||
export const getStaticProps: GetStaticProps<PageProps> = async () => {
|
||||
const { data: tags = [] } = await unbodyApi.getTopics(true)
|
||||
const { data: highlighted } = await unbodyApi.getHighlightedPosts()
|
||||
const { data: latest = [] } = await unbodyApi.getRecentPosts({
|
||||
const { data: latest } = await unbodyApi.getRecentPosts({
|
||||
skip: 0,
|
||||
limit: 15,
|
||||
})
|
||||
|
@ -46,7 +46,10 @@ export const getStaticProps: GetStaticProps<PageProps> = async () => {
|
|||
data: {
|
||||
tags,
|
||||
shows,
|
||||
latest,
|
||||
latest: {
|
||||
data: latest?.data || [],
|
||||
hasMore: latest?.hasMore,
|
||||
},
|
||||
highlighted,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,12 +5,13 @@ import { GetStaticPropsContext } from 'next'
|
|||
import { useRouter } from 'next/router'
|
||||
import { ReactNode } from 'react'
|
||||
import { DefaultLayout } from '../../../layouts/DefaultLayout'
|
||||
import { ApiPaginatedPayload } from '../../../types/data.types'
|
||||
import { LPE } from '../../../types/lpe.types'
|
||||
import { getPostLink } from '../../../utils/route.utils'
|
||||
|
||||
interface PodcastShowProps {
|
||||
show: LPE.Podcast.Show
|
||||
latestEpisodes: LPE.Podcast.Document[]
|
||||
latestEpisodes: ApiPaginatedPayload<LPE.Podcast.Document[]>
|
||||
highlightedEpisodes: LPE.Podcast.Document[]
|
||||
errors: string | null
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import { useMemo } from 'react'
|
||||
import { api } from '../services/api.service'
|
||||
import { ApiPaginatedPayload } from '../types/data.types'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
|
||||
export const useRecentEpisodes = ({
|
||||
initialData = [],
|
||||
initialData = { data: [], hasMore: true },
|
||||
limit = 10,
|
||||
showSlug,
|
||||
}: {
|
||||
initialData?: LPE.Podcast.Document[]
|
||||
initialData?: ApiPaginatedPayload<LPE.Podcast.Document[]>
|
||||
showSlug: string
|
||||
limit?: number
|
||||
}) => {
|
||||
const query = useInfiniteQuery(
|
||||
['recent-episodes', showSlug, initialData, limit],
|
||||
async ({ pageParam }) => {
|
||||
const firstPageLimit = initialData.length
|
||||
const firstPageLimit = initialData.data.length
|
||||
const _limit = pageParam === 1 ? firstPageLimit : limit
|
||||
const skip =
|
||||
pageParam === 1 ? 0 : (pageParam - 2) * limit + firstPageLimit
|
||||
|
@ -24,8 +25,8 @@ export const useRecentEpisodes = ({
|
|||
.getLatestEpisodes({ skip, limit: _limit, showSlug })
|
||||
.then((res) => ({
|
||||
page: pageParam,
|
||||
posts: res.data,
|
||||
hasMore: res.data.length !== 0,
|
||||
posts: res.data.data,
|
||||
hasMore: res.data.hasMore,
|
||||
}))
|
||||
},
|
||||
{
|
||||
|
@ -34,8 +35,8 @@ export const useRecentEpisodes = ({
|
|||
pages: [
|
||||
{
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
posts: initialData,
|
||||
posts: initialData.data,
|
||||
hasMore: initialData?.hasMore,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import { useMemo } from 'react'
|
||||
import { api } from '../services/api.service'
|
||||
import { ApiPaginatedPayload } from '../types/data.types'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
|
||||
export const useRecentPosts = ({
|
||||
initialData = [],
|
||||
initialData,
|
||||
limit = 10,
|
||||
}: {
|
||||
initialData?: LPE.Post.Document[]
|
||||
initialData?: ApiPaginatedPayload<LPE.Post.Document[]>
|
||||
limit?: number
|
||||
}) => {
|
||||
const query = useInfiniteQuery(
|
||||
['latest-posts', initialData, limit],
|
||||
async ({ pageParam }) => {
|
||||
const firstPageLimit = initialData.length
|
||||
const firstPageLimit = initialData?.data.length || 0
|
||||
const _limit = pageParam === 1 ? firstPageLimit : limit
|
||||
const skip =
|
||||
pageParam === 1 ? 0 : (pageParam - 2) * limit + firstPageLimit
|
||||
|
||||
return api.getRecentPosts({ skip, limit: _limit }).then((res) => ({
|
||||
page: pageParam,
|
||||
posts: res.data,
|
||||
hasMore: res.data.length !== 0,
|
||||
posts: res.data.data,
|
||||
hasMore: res.data.hasMore,
|
||||
}))
|
||||
},
|
||||
{
|
||||
|
@ -30,8 +31,8 @@ export const useRecentPosts = ({
|
|||
pages: [
|
||||
{
|
||||
page: 1,
|
||||
hasMore: true,
|
||||
posts: initialData,
|
||||
hasMore: initialData?.hasMore,
|
||||
posts: initialData?.data || [],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ApiResponse } from '../types/data.types'
|
||||
import { ApiPaginatedResponse, ApiResponse } from '../types/data.types'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
|
||||
export class ApiService {
|
||||
|
@ -8,7 +8,7 @@ export class ApiService {
|
|||
}: {
|
||||
skip?: number
|
||||
limit?: number
|
||||
}): Promise<ApiResponse<LPE.Post.Document[]>> =>
|
||||
}): Promise<ApiPaginatedResponse<LPE.Post.Document[]>> =>
|
||||
fetch(`/api/posts?skip=${skip}&limit=${limit}`)
|
||||
.then((res) => res.json())
|
||||
.catch((e) => {
|
||||
|
@ -24,7 +24,7 @@ export class ApiService {
|
|||
skip?: number
|
||||
limit?: number
|
||||
showSlug: string
|
||||
}): Promise<ApiResponse<LPE.Podcast.Document[]>> =>
|
||||
}): Promise<ApiPaginatedResponse<LPE.Podcast.Document[]>> =>
|
||||
fetch(`/api/podcasts/${showSlug}/episodes?skip=${skip}&limit=${limit}`)
|
||||
.then((res) => res.json())
|
||||
.catch((e) => {
|
||||
|
|
|
@ -13,7 +13,11 @@ import {
|
|||
Txt2VecOpenAiGetObjectsTextBlockNearTextInpObj,
|
||||
} from '../../lib/unbody/unbody.generated'
|
||||
import { getWebhookData } from '../../pages/api/webhook'
|
||||
import { ApiResponse, SearchResultItem } from '../../types/data.types'
|
||||
import {
|
||||
ApiPaginatedPayload,
|
||||
ApiResponse,
|
||||
SearchResultItem,
|
||||
} from '../../types/data.types'
|
||||
import { LPE } from '../../types/lpe.types'
|
||||
import {
|
||||
CreatePromiseResult,
|
||||
|
@ -60,8 +64,10 @@ export class UnbodyService {
|
|||
|
||||
initialData: {
|
||||
posts: LPE.Post.Document[]
|
||||
articles: LPE.Article.Data[]
|
||||
episodes: LPE.Podcast.Document[]
|
||||
staticPages: LPE.StaticPage.Document[]
|
||||
} = { posts: [], staticPages: [] }
|
||||
} = { articles: [], episodes: [], posts: [], staticPages: [] }
|
||||
initialDataPromise: CreatePromiseResult<any> = null as any
|
||||
|
||||
constructor(private apiKey: string, private projectId: string) {
|
||||
|
@ -136,6 +142,8 @@ export class UnbodyService {
|
|||
|
||||
this.initialData = {
|
||||
posts,
|
||||
articles,
|
||||
episodes,
|
||||
staticPages,
|
||||
}
|
||||
callback(this.initialData)
|
||||
|
@ -892,13 +900,22 @@ export class UnbodyService {
|
|||
skip?: number
|
||||
limit?: number
|
||||
}) =>
|
||||
this.getPodcastEpisodes({
|
||||
skip,
|
||||
limit,
|
||||
showSlug,
|
||||
highlighted: 'include',
|
||||
populateShow: false,
|
||||
})
|
||||
this.handleRequest<ApiPaginatedPayload<LPE.Podcast.Document[]>>(
|
||||
async () => {
|
||||
await this.loadInitialData()
|
||||
let episodes = [...this.initialData.episodes]
|
||||
if (showSlug)
|
||||
episodes = episodes.filter((ep) => ep.show?.slug === showSlug)
|
||||
|
||||
const data = episodes.slice(skip, skip + limit)
|
||||
|
||||
return {
|
||||
data,
|
||||
hasMore: episodes.length > skip + limit,
|
||||
}
|
||||
},
|
||||
{ data: [], hasMore: false },
|
||||
)
|
||||
|
||||
getRecentPosts = async ({
|
||||
limit = 10,
|
||||
|
@ -907,12 +924,23 @@ export class UnbodyService {
|
|||
limit?: number
|
||||
skip?: number
|
||||
}) =>
|
||||
this.handleRequest(async () => {
|
||||
await this.loadInitialData()
|
||||
const { posts } = this.initialData
|
||||
this.handleRequest<ApiPaginatedPayload<LPE.Post.Document[]>>(
|
||||
async () => {
|
||||
await this.loadInitialData()
|
||||
const { posts } = this.initialData
|
||||
|
||||
return posts.slice(skip, skip + limit)
|
||||
}, [])
|
||||
const data = posts.slice(skip, skip + limit)
|
||||
|
||||
return {
|
||||
data,
|
||||
hasMore: posts.length > skip + limit,
|
||||
}
|
||||
},
|
||||
{
|
||||
data: [],
|
||||
hasMore: false,
|
||||
},
|
||||
)
|
||||
|
||||
getHighlightedPosts = async () =>
|
||||
this.handleRequest<LPE.Post.Document[]>(async () => {
|
||||
|
|
|
@ -10,6 +10,9 @@ export type ApiResponse<T> = {
|
|||
errors: any
|
||||
}
|
||||
|
||||
export type ApiPaginatedPayload<T> = { data: T; hasMore: boolean }
|
||||
export type ApiPaginatedResponse<T> = ApiResponse<ApiPaginatedPayload<T>>
|
||||
|
||||
export type SearchResultItem<T> = {
|
||||
doc: T
|
||||
score: number
|
||||
|
|
Loading…
Reference in New Issue