Skip to content

Commit

Permalink
feat(blog): add related posts (#976)
Browse files Browse the repository at this point in the history
* feat(blog): add related posts

* refactor(blog): props loader related posts

* feat(blog): jsdoc and refactors

* chore(deno): eslint
  • Loading branch information
luanargolodev authored Jan 6, 2025
1 parent c93ac15 commit c1754b7
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 6 deletions.
96 changes: 96 additions & 0 deletions blog/loaders/BlogRelatedPosts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* @title BlogRelatedPosts
* @description Retrieves a list of blog related posts.
*
* @param props - The props for the blog related post list.
* @param req - The request object.
* @param ctx - The application context.
* @returns A promise that resolves to an array of blog related posts.
*/
import { RequestURLParam } from "../../website/functions/requestToParam.ts";
import { AppContext } from "../mod.ts";
import { BlogPost, SortBy } from "../types.ts";
import handlePosts, { slicePosts } from "../utils/handlePosts.ts";
import { getRecordsByPath } from "../utils/records.ts";

const COLLECTION_PATH = "collections/blog/posts";
const ACCESSOR = "post";

export interface Props {
/**
* @title Items per page
* @description Number of posts per page to display.
*/
count?: number;
/**
* @title Page query parameter
* @description The current page number. Defaults to 1.
*/
page?: number;
/**
* @title Category Slug
* @description Filter by a specific category slug.
*/
slug?: RequestURLParam | string[];
/**
* @title Page sorting parameter
* @description The sorting option. Default is "date_desc"
*/
sortBy?: SortBy;
/**
* @description Overrides the query term at url
*/
query?: string;
/**
* @title Exclude Post Slug
* @description Excludes a post slug from the list
*/
excludePostSlug?: RequestURLParam | string;
}

/**
* @title BlogRelatedPosts
* @description Retrieves a list of blog related posts.
*
* @param props - The props for the blog related post list.
* @param req - The request object.
* @param ctx - The application context.
* @returns A promise that resolves to an array of blog related posts.
*/

export type BlogRelatedPosts = BlogPost[] | null;

export default async function BlogRelatedPosts(
{ page, count, slug, sortBy, query, excludePostSlug }: Props,
req: Request,
ctx: AppContext,
): Promise<BlogRelatedPosts> {
const url = new URL(req.url);
const postsPerPage = Number(count ?? url.searchParams.get("count") ?? 12);
const pageNumber = Number(page ?? url.searchParams.get("page") ?? 1);
const pageSort = sortBy ?? (url.searchParams.get("sortBy") as SortBy) ??
"date_desc";
const term = query ?? url.searchParams.get("q") ?? undefined;

const posts = await getRecordsByPath<BlogPost>(
ctx,
COLLECTION_PATH,
ACCESSOR,
);

const handledPosts = handlePosts(
posts,
pageSort,
slug,
term,
excludePostSlug,
);

if (!handledPosts) {
return null;
}

const slicedPosts = slicePosts(handledPosts, pageNumber, postsPerPage);

return slicedPosts.length > 0 ? slicedPosts : null;
}
2 changes: 1 addition & 1 deletion blog/loaders/BlogpostList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default async function BlogPostList(
ctx: AppContext,
): Promise<BlogPost[] | null> {
const url = new URL(req.url);
const postsPerPage = Number(count ?? url.searchParams.get("count"));
const postsPerPage = Number(count ?? url.searchParams.get("count") ?? 12);
const pageNumber = Number(page ?? url.searchParams.get("page") ?? 1);
const pageSort = sortBy ?? url.searchParams.get("sortBy") as SortBy ??
"date_desc";
Expand Down
2 changes: 2 additions & 0 deletions blog/manifest.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as $$$5 from "./loaders/BlogpostListing.ts";
import * as $$$2 from "./loaders/BlogPostPage.ts";
import * as $$$6 from "./loaders/Category.ts";
import * as $$$7 from "./loaders/GetCategories.ts";
import * as $$$8 from "./loaders/BlogRelatedPosts.ts";
import * as $$$$$$0 from "./sections/Seo/SeoBlogPost.tsx";
import * as $$$$$$1 from "./sections/Seo/SeoBlogPostListing.tsx";
import * as $$$$$$2 from "./sections/Template.tsx";
Expand All @@ -24,6 +25,7 @@ const manifest = {
"blog/loaders/BlogPostPage.ts": $$$2,
"blog/loaders/Category.ts": $$$6,
"blog/loaders/GetCategories.ts": $$$7,
"blog/loaders/BlogRelatedPosts.ts": $$$8,
},
"sections": {
"blog/sections/Seo/SeoBlogPost.tsx": $$$$$$0,
Expand Down
32 changes: 27 additions & 5 deletions blog/utils/handlePosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ export const filterPostsByTerm = (posts: BlogPost[], term: string) =>
)
);

/**
* Returns an filtered BlogPost list
*
* @param posts Posts to be handled
* @param slug Category Slug to be filter
*/
export const filterRelatedPosts = (
posts: BlogPost[],
slug: string[],
) =>
posts.filter(
({ categories }) => categories.find((c) => slug.includes(c.slug)),
);

/**
* Returns an filtered and sorted BlogPost list
*
Expand All @@ -77,11 +91,15 @@ export const slicePosts = (

export const filterPosts = (
posts: BlogPost[],
slug?: string,
slug?: string | string[],
term?: string,
): BlogPost[] => {
if (term) return filterPostsByTerm(posts, term);
if (slug) return filterPostsByCategory(posts, slug);
if (typeof slug === "string") return filterPostsByCategory(posts, slug);
if (Array.isArray(slug)) {
return filterRelatedPosts(posts, slug);
}

return posts;
};

Expand All @@ -90,16 +108,20 @@ export const filterPosts = (
*
* @param posts Posts to be handled
* @param sortBy Sort option (must be: "date_desc" | "date_asc" | "title_asc" | "title_desc" )
* @param slug Category slug to be filter
* @param slug Category slug or an array of slugs to be filtered
* @param term Term to be filter
* @param excludePostSlug Post slug to be excluded
*/
export default function handlePosts(
posts: BlogPost[],
sortBy: SortBy,
slug?: string,
slug?: string | string[],
term?: string,
excludePostSlug?: string,
) {
const filteredPosts = filterPosts(posts, slug, term);
const filteredPosts = filterPosts(posts, slug, term).filter(
({ slug: postSlug }) => postSlug !== excludePostSlug,
);

if (!filteredPosts || filteredPosts.length === 0) {
return null;
Expand Down

0 comments on commit c1754b7

Please sign in to comment.