From 77408fb8928825f6307dca7a09e836c31612ab70 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Sun, 4 Jan 2026 21:55:15 -0500 Subject: [PATCH] revert due to filtering issues --- src/routes/blog/index.tsx | 263 +++++++++----------------------------- 1 file changed, 63 insertions(+), 200 deletions(-) diff --git a/src/routes/blog/index.tsx b/src/routes/blog/index.tsx index c04eedd..d054556 100644 --- a/src/routes/blog/index.tsx +++ b/src/routes/blog/index.tsx @@ -1,4 +1,4 @@ -import { Show, createSignal, onMount, lazy } from "solid-js"; +import { Show } from "solid-js"; import { useSearchParams, A, query } from "@solidjs/router"; import { Title } from "@solidjs/meta"; import { createAsync } from "@solidjs/router"; @@ -6,15 +6,11 @@ import { getRequestEvent } from "solid-js/web"; import PostSortingSelect from "~/components/blog/PostSortingSelect"; import TagSelector from "~/components/blog/TagSelector"; import PostSorting from "~/components/blog/PostSorting"; +import PublishStatusToggle from "~/components/blog/PublishStatusToggle"; import { TerminalSplash } from "~/components/TerminalSplash"; import { CACHE_CONFIG } from "~/config"; -const PublishStatusToggle = lazy(() => import("~/components/blog/PublishStatusToggle")); - -const POSTS_PER_PAGE = 12; - -// Separate query for all tags (needed for TagSelector) -const getAllTags = query(async () => { +const getPosts = query(async () => { "use server"; const { ConnectionFactory, getPrivilegeLevel } = await import("~/server/utils"); @@ -23,61 +19,17 @@ const getAllTags = query(async () => { const privilegeLevel = await getPrivilegeLevel(event.nativeEvent); return withCache( - `all-tags-${privilegeLevel}`, + `posts-${privilegeLevel}`, CACHE_CONFIG.BLOG_POSTS_LIST_CACHE_TTL_MS, async () => { const conn = ConnectionFactory(); - const tagsQuery = ` - SELECT t.value, t.post_id - FROM Tag t - JOIN Post p ON t.post_id = p.id - ${privilegeLevel !== "admin" ? "WHERE p.published = TRUE" : ""} - ORDER BY t.value ASC - `; - - const tagsResult = await conn.execute(tagsQuery); - const tags = tagsResult.rows; - - const tagMap: Record = {}; - tags.forEach((tag: any) => { - const key = `${tag.value}`; - tagMap[key] = (tagMap[key] || 0) + 1; - }); - - return { tagMap, privilegeLevel }; - } - ); -}, "all-tags"); - -const getPosts = query(async (page: number = 1) => { - "use server"; - const { ConnectionFactory, getPrivilegeLevel } = - await import("~/server/utils"); - const { withCache } = await import("~/server/cache"); - const event = getRequestEvent()!; - const privilegeLevel = await getPrivilegeLevel(event.nativeEvent); - - return withCache( - `posts-${privilegeLevel}-page-${page}`, - CACHE_CONFIG.BLOG_POSTS_LIST_CACHE_TTL_MS, - async () => { - const conn = ConnectionFactory(); - const offset = (page - 1) * POSTS_PER_PAGE; - - // Get total count first - let countQuery = `SELECT COUNT(*) as total FROM Post p`; - if (privilegeLevel !== "admin") { - countQuery += ` WHERE p.published = TRUE`; - } - const countResult = await conn.execute(countQuery); - const totalPosts = (countResult.rows[0] as any).total; - let postsQuery = ` SELECT p.id, p.title, p.subtitle, + p.body, p.banner_photo, p.date, p.published, @@ -96,185 +48,96 @@ const getPosts = query(async (page: number = 1) => { postsQuery += ` WHERE p.published = TRUE`; } - postsQuery += ` GROUP BY p.id, p.title, p.subtitle, p.banner_photo, p.date, p.published, p.category, p.author_id, p.reads, p.attachments`; - postsQuery += ` ORDER BY p.date ASC`; - postsQuery += ` LIMIT ${POSTS_PER_PAGE} OFFSET ${offset};`; + postsQuery += ` GROUP BY p.id, p.title, p.subtitle, p.body, p.banner_photo, p.date, p.published, p.category, p.author_id, p.reads, p.attachments`; + postsQuery += ` ORDER BY p.date ASC;`; const postsResult = await conn.execute(postsQuery); const posts = postsResult.rows; - // Only fetch tags for the posts we're returning - const postIds = posts.map((p: any) => p.id).join(","); - const tagsQuery = postIds - ? ` + const tagsQuery = ` SELECT t.value, t.post_id FROM Tag t - WHERE t.post_id IN (${postIds}) + JOIN Post p ON t.post_id = p.id + ${privilegeLevel !== "admin" ? "WHERE p.published = TRUE" : ""} ORDER BY t.value ASC - ` - : `SELECT t.value, t.post_id FROM Tag t WHERE 1=0`; + `; const tagsResult = await conn.execute(tagsQuery); const tags = tagsResult.rows; - return { - posts, - tags, - hasMore: offset + posts.length < totalPosts, - totalPosts - }; + const tagMap: Record = {}; + tags.forEach((tag: any) => { + const key = `${tag.value}`; + tagMap[key] = (tagMap[key] || 0) + 1; + }); + + return { posts, tags, tagMap, privilegeLevel }; } ); }, "posts"); export default function BlogIndex() { const [searchParams] = useSearchParams(); - const [currentPage, setCurrentPage] = createSignal(1); - const [allPosts, setAllPosts] = createSignal([]); - const [allTags, setAllTags] = createSignal([]); - const [hasMore, setHasMore] = createSignal(true); - const [isLoading, setIsLoading] = createSignal(false); - let sentinelRef: HTMLDivElement | undefined; - const sort = () => { - const sortParam = searchParams.sort; - return Array.isArray(sortParam) ? sortParam[0] : sortParam || "newest"; - }; - const filters = () => { - const filterParam = searchParams.filter; - return filterParam - ? Array.isArray(filterParam) - ? filterParam[0] - : filterParam - : undefined; - }; - const include = () => { - const includeParam = searchParams.include; - return includeParam - ? Array.isArray(includeParam) - ? includeParam[0] - : includeParam - : undefined; - }; - const status = () => { - const statusParam = searchParams.status; - return statusParam - ? Array.isArray(statusParam) - ? statusParam[0] - : statusParam - : undefined; - }; + const sort = () => searchParams.sort || "newest"; + const filters = () => + "filter" in searchParams ? searchParams.filter : undefined; + const include = () => + "include" in searchParams ? searchParams.include : undefined; + const status = () => + "status" in searchParams ? searchParams.status : undefined; - // Load initial page and tag data - const initialData = createAsync(() => getPosts(1), { deferStream: true }); - const tagsData = createAsync(() => getAllTags(), { deferStream: true }); - - // Initialize with first page data - const initializeData = () => { - const firstPage = initialData(); - if (firstPage) { - setAllPosts(firstPage.posts); - setAllTags(firstPage.tags); - setHasMore(firstPage.hasMore); - } - }; - - // Load more posts - const loadMorePosts = async () => { - if (isLoading() || !hasMore()) return; - - setIsLoading(true); - const nextPage = currentPage() + 1; - - try { - const newData = await getPosts(nextPage); - setAllPosts((prev) => [...prev, ...newData.posts]); - setAllTags((prev) => [...prev, ...newData.tags]); - setHasMore(newData.hasMore); - setCurrentPage(nextPage); - } catch (error) { - console.error("Error loading more posts:", error); - } finally { - setIsLoading(false); - } - }; - - // Set up IntersectionObserver for infinite scroll - onMount(() => { - initializeData(); - - const observer = new IntersectionObserver( - (entries) => { - if (entries[0]?.isIntersecting) { - loadMorePosts(); - } - }, - { rootMargin: "200px" } - ); - - if (sentinelRef) { - observer.observe(sentinelRef); - } - - return () => observer.disconnect(); - }); + const data = createAsync(() => getPosts(), { deferStream: true }); return ( <> Blog | Michael Freno
- }> -
- + }> + {(loadedData) => ( + <> +
+ - 0} - > - - + 0}> + + - - - + + + - - - -
- 0} - fallback={
No posts yet!
} - > -
- - - {/* Sentinel element for infinite scroll */} - -
- -
Loading more posts...
-
+ 0} + fallback={
No posts yet!
} + > +
+
-
-
+ + )}