feat(blog): add rich listing filters

This commit is contained in:
2026-06-11 21:21:43 +03:30
parent 3ec931aabb
commit e89fcfb20e
4 changed files with 524 additions and 74 deletions

View File

@@ -71,15 +71,39 @@ async function requestJson<T>(
return (await response.json()) as T;
}
export async function getPublicPosts(options?: { search?: string; limit?: number }) {
export async function getPublicPosts(options?: {
search?: string;
category?: string;
tag?: string[];
author?: string[];
limit?: number;
}) {
const search = options?.search?.trim();
const category = options?.category?.trim();
const tag = options?.tag?.filter(Boolean) ?? [];
const author = options?.author?.filter(Boolean) ?? [];
return requestJson<Types.PostListSchema[]>("/api/blog/posts", {
params: {
limit: options?.limit ?? 50,
...(search ? { search } : {}),
...(category ? { category } : {}),
...(tag.length ? { tag } : {}),
...(author.length ? { author } : {}),
},
revalidate: search ? 60 : DEFAULT_REVALIDATE_SECONDS,
revalidate: search || category || tag.length || author.length ? 60 : DEFAULT_REVALIDATE_SECONDS,
});
}
export async function getBlogFilters() {
return requestJson<Types.BlogFiltersSchema>("/api/blog/filters", {
revalidate: DEFAULT_REVALIDATE_SECONDS,
});
}
export async function getBlogBanners() {
return requestJson<Types.BlogBannerSchema[]>("/api/blog/banners", {
revalidate: DEFAULT_REVALIDATE_SECONDS,
});
}

View File

@@ -229,6 +229,7 @@ export interface PostListSchema {
username: string;
first_name: string;
last_name: string;
bio?: string | null;
profile_picture?: string;
profile_picture_thumbnail_url?: string | null;
profile_picture_preview_url?: string | null;
@@ -238,7 +239,23 @@ export interface PostListSchema {
name: string;
slug: string;
description?: string;
parent_id?: number | null;
};
category_path?: Array<{
id: number;
name: string;
slug: string;
}>;
writers?: Array<{
id: number;
username: string;
first_name: string;
last_name: string;
bio?: string | null;
profile_picture?: string;
profile_picture_thumbnail_url?: string | null;
profile_picture_preview_url?: string | null;
}>;
tags: Array<{
id: number;
name: string;
@@ -276,6 +293,7 @@ export interface PostCreateSchema {
excerpt?: string;
category_id?: number | null;
tag_ids?: number[];
writer_ids?: number[];
is_featured?: boolean;
status?: 'draft' | 'submitted' | 'changes_requested' | 'published' | 'archived';
seo_title?: string;
@@ -323,14 +341,23 @@ export interface CommentSchema {
username: string;
first_name: string;
last_name: string;
bio?: string | null;
profile_picture?: string | null;
profile_picture_thumbnail_url?: string | null;
profile_picture_preview_url?: string | null;
};
post_id: number;
post_title: string;
post_slug: string;
parent_id?: number;
created_at: string;
updated_at?: string;
is_approved: boolean;
is_hidden?: boolean;
is_deleted?: boolean;
hidden_at?: string | null;
deleted_at?: string | null;
hidden_replies_count?: number;
replies?: CommentSchema[];
}
@@ -339,6 +366,19 @@ export interface CommentCreateSchema {
parent_id?: number;
}
export interface CommentUpdateSchema {
content: string;
}
export interface BlogBannerSchema {
id: number;
title?: string;
alt_text?: string;
image_url: string;
url: string;
sort_order: number;
}
export interface BlogInteractionSchema {
liked: boolean;
saved: boolean;
@@ -359,6 +399,7 @@ export interface CategorySchema {
name: string;
slug: string;
description?: string;
parent_id?: number | null;
created_at: string;
}
@@ -369,6 +410,36 @@ export interface TagSchema {
created_at: string;
}
export interface BlogFilterCategory {
id: number;
name: string;
slug: string;
parent_id?: number | null;
post_count: number;
children: BlogFilterCategory[];
}
export interface BlogFilterTag {
id: number;
name: string;
slug: string;
post_count: number;
}
export interface BlogFilterAuthor {
id: number;
username: string;
first_name: string;
last_name: string;
post_count: number;
}
export interface BlogFiltersSchema {
categories: BlogFilterCategory[];
tags: BlogFilterTag[];
authors: BlogFilterAuthor[];
}
// Events Types
export interface EventListItemSchema {
id: number;