diff --git a/packages/backend/src/graphql/resolvers/articles.ts b/packages/backend/src/graphql/resolvers/articles.ts index 5c048bd..f5d79b3 100644 --- a/packages/backend/src/graphql/resolvers/articles.ts +++ b/packages/backend/src/graphql/resolvers/articles.ts @@ -1,7 +1,7 @@ import { builder } from "../builder"; import { ArticleType, ArticleListType, AdminArticleListType } from "../types/index"; import { articles, users } from "../../db/schema/index"; -import { eq, and, lte, desc, asc, ilike, or, count, arrayContains, type SQL } from "drizzle-orm"; +import { eq, and, lte, desc, asc, ilike, or, count, arrayContains, isNotNull, type SQL } from "drizzle-orm"; import { requireAdmin } from "../../lib/acl"; import type { DB } from "../../db/connection"; @@ -74,6 +74,20 @@ builder.queryField("articles", (t) => }), ); +builder.queryField("articleCategories", (t) => + t.field({ + type: ["String"], + resolve: async (_root, _args, ctx) => { + const rows = await ctx.db + .selectDistinct({ category: articles.category }) + .from(articles) + .where(and(lte(articles.publish_date, new Date()), isNotNull(articles.category))) + .orderBy(asc(articles.category)); + return rows.map((r) => r.category!); + }, + }), +); + builder.queryField("article", (t) => t.field({ type: ArticleType, diff --git a/packages/frontend/src/lib/services.ts b/packages/frontend/src/lib/services.ts index 5c87929..407db69 100644 --- a/packages/frontend/src/lib/services.ts +++ b/packages/frontend/src/lib/services.ts @@ -298,6 +298,23 @@ export async function getArticles( }); } +const ARTICLE_CATEGORIES_QUERY = gql` + query GetArticleCategories { + articleCategories + } +`; + +export async function getArticleCategories( + fetchFn?: typeof globalThis.fetch, +): Promise { + return loggedApiCall("getArticleCategories", async () => { + const data = await getGraphQLClient(fetchFn).request<{ articleCategories: string[] }>( + ARTICLE_CATEGORIES_QUERY, + ); + return data.articleCategories; + }); +} + const ARTICLE_BY_SLUG_QUERY = gql` query GetArticleBySlug($slug: String!) { article(slug: $slug) { diff --git a/packages/frontend/src/routes/magazine/+page.server.ts b/packages/frontend/src/routes/magazine/+page.server.ts index ab8e039..55b9e37 100644 --- a/packages/frontend/src/routes/magazine/+page.server.ts +++ b/packages/frontend/src/routes/magazine/+page.server.ts @@ -1,4 +1,4 @@ -import { getArticles } from "$lib/services"; +import { getArticles, getArticleCategories } from "$lib/services"; const LIMIT = 24; @@ -9,6 +9,9 @@ export async function load({ fetch, url }) { const page = Math.max(1, parseInt(url.searchParams.get("page") || "1", 10)); const offset = (page - 1) * LIMIT; - const result = await getArticles({ search, sortBy: sort, category, offset, limit: LIMIT }, fetch); - return { ...result, search, sort, category, page, limit: LIMIT }; + const [result, categories] = await Promise.all([ + getArticles({ search, sortBy: sort, category, offset, limit: LIMIT }, fetch), + getArticleCategories(fetch), + ]); + return { ...result, search, sort, category, page, limit: LIMIT, categories }; } diff --git a/packages/frontend/src/routes/magazine/+page.svelte b/packages/frontend/src/routes/magazine/+page.svelte index 0180b2d..91182b8 100644 --- a/packages/frontend/src/routes/magazine/+page.svelte +++ b/packages/frontend/src/routes/magazine/+page.svelte @@ -82,12 +82,10 @@ value={data.category ?? "all"} options={[ { value: "all", label: $_("magazine.categories.all") }, - { value: "photography", label: $_("magazine.categories.photography") }, - { value: "production", label: $_("magazine.categories.production") }, - { value: "interview", label: $_("magazine.categories.interview") }, - { value: "psychology", label: $_("magazine.categories.psychology") }, - { value: "trends", label: $_("magazine.categories.trends") }, - { value: "spotlight", label: $_("magazine.categories.spotlight") }, + ...data.categories.map((c) => ({ + value: c, + label: $_(`magazine.categories.${c}`, { default: c }), + })), ]} onchange={(v) => setParam("category", v)} />