diff --git a/frontend/app/[locale]/blog/[slug]/PostDetails.tsx b/frontend/app/[locale]/blog/[slug]/PostDetails.tsx index fdf5efb8..34169551 100644 --- a/frontend/app/[locale]/blog/[slug]/PostDetails.tsx +++ b/frontend/app/[locale]/blog/[slug]/PostDetails.tsx @@ -5,6 +5,8 @@ import { getTranslations } from 'next-intl/server'; import { client } from '@/client'; import { Link } from '@/i18n/routing'; +export const revalidate = 0; + type SocialLink = { _key?: string; platform?: string; @@ -116,11 +118,15 @@ export default async function PostDetails({ const slugParam = String(slug || '').trim(); if (!slugParam) return notFound(); - const post: Post | null = await client.fetch(query, { + const post: Post | null = await client + .withConfig({ useCdn: false }) + .fetch(query, { slug: slugParam, locale, }); - const recommendedAll: Post[] = await client.fetch(recommendedQuery, { + const recommendedAll: Post[] = await client + .withConfig({ useCdn: false }) + .fetch(recommendedQuery, { slug: slugParam, locale, }); @@ -156,7 +162,7 @@ export default async function PostDetails({ href={`/blog?category=${encodeURIComponent(post.categories[0])}`} className="inline-flex items-center gap-1 hover:text-[#ff00ff] transition" > - {post.categories[0]} + {post.categories[0] === 'Growth' ? 'Career' : post.categories[0]} )} diff --git a/frontend/app/[locale]/blog/category/[category]/page.tsx b/frontend/app/[locale]/blog/category/[category]/page.tsx new file mode 100644 index 00000000..5de76c23 --- /dev/null +++ b/frontend/app/[locale]/blog/category/[category]/page.tsx @@ -0,0 +1,101 @@ +import groq from 'groq'; +import { notFound } from 'next/navigation'; +import { getTranslations } from 'next-intl/server'; +import { client } from '@/client'; +import { BlogCategoryGrid } from '@/components/blog/BlogCategoryGrid'; + +export const revalidate = 0; + +type Author = { + name?: string; + image?: string; +}; + +type Post = { + _id: string; + title: string; + slug: { current: string }; + publishedAt?: string; + categories?: string[]; + mainImage?: string; + body?: any[]; + author?: Author; +}; + +type Category = { + _id: string; + title: string; +}; + +const categoriesQuery = groq` + *[_type == "category"] | order(orderRank asc) { + _id, + title + } +`; + +export default async function BlogCategoryPage({ + params, +}: { + params: Promise<{ locale: string; category: string }>; +}) { + const { locale, category } = await params; + const t = await getTranslations({ locale, namespace: 'blog' }); + const categoryKey = String(category || '').toLowerCase(); + const categories: Category[] = await client + .withConfig({ useCdn: false }) + .fetch(categoriesQuery); + const matchedCategory = categories.find( + item => slugify(item.title) === categoryKey + ); + + if (!matchedCategory) return notFound(); + const categoryTitle = matchedCategory.title; + const displayTitle = + categoryTitle === 'Growth' ? 'Career' : categoryTitle; + + const posts: Post[] = await client.withConfig({ useCdn: false }).fetch( + groq` + *[_type == "post" && defined(slug.current) && $category in categories[]->title] + | order(publishedAt desc) { + _id, + "title": coalesce(title[$locale], title[lower($locale)], title.uk, title.en, title.pl, title), + slug, + publishedAt, + "categories": categories[]->title, + "body": coalesce(body[$locale], body[lower($locale)], body.uk, body.en, body.pl, body)[]{ + ..., + children[]{ text } + }, + "mainImage": mainImage.asset->url, + "author": author->{ + "name": coalesce(name[$locale], name[lower($locale)], name.uk, name.en, name.pl, name), + "image": image.asset->url + } + } + `, + { locale, category: categoryTitle } + ); + + return ( +
+

+ {displayTitle} +

+
+ +
+ {!posts.length && ( +

{t('noPosts')}

+ )} +
+ ); +} + +function slugify(value: string) { + return value + .toLowerCase() + .trim() + .replace(/[^a-z0-9\s-]/g, '') + .replace(/\s+/g, '-'); +} diff --git a/frontend/app/[locale]/blog/page.tsx b/frontend/app/[locale]/blog/page.tsx index ecc85341..bd751d04 100644 --- a/frontend/app/[locale]/blog/page.tsx +++ b/frontend/app/[locale]/blog/page.tsx @@ -3,6 +3,8 @@ import { getTranslations } from 'next-intl/server'; import { client } from '@/client'; import BlogFilters from '@/components/blog/BlogFilters'; +export const revalidate = 0; + export async function generateMetadata({ params, }: { @@ -25,7 +27,7 @@ export default async function BlogPage({ const { locale } = await params; const t = await getTranslations({ locale, namespace: 'blog' }); - const posts = await client.fetch( + const posts = await client.withConfig({ useCdn: false }).fetch( groq` *[_type == "post" && defined(slug.current)] | order(publishedAt desc) { @@ -62,7 +64,7 @@ export default async function BlogPage({ `, { locale } ); - const categories = await client.fetch( + const categories = await client.withConfig({ useCdn: false }).fetch( groq` *[_type == "category"] | order(orderRank asc) { _id, diff --git a/frontend/app/[locale]/layout.tsx b/frontend/app/[locale]/layout.tsx index f7a3e20a..b8966748 100644 --- a/frontend/app/[locale]/layout.tsx +++ b/frontend/app/[locale]/layout.tsx @@ -3,11 +3,13 @@ import { Toaster } from 'sonner'; import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server'; import { notFound } from 'next/navigation'; +import groq from 'groq'; import { locales } from '@/i18n/config'; import Footer from '@/components/shared/Footer'; import { ThemeProvider } from '@/components/theme/ThemeProvider'; import { getCurrentUser } from '@/lib/auth'; +import { client } from '@/client'; import { MainSwitcher } from '@/components/header/MainSwitcher'; import { AppChrome } from '@/components/header/AppChrome'; @@ -29,6 +31,16 @@ export default async function LocaleLayout({ const messages = await getMessages({ locale }); const user = await getCurrentUser(); + const blogCategories: Array<{ _id: string; title: string }> = await client + .withConfig({ useCdn: false }) + .fetch( + groq` + *[_type == "category"] | order(orderRank asc) { + _id, + title + } + ` + ); const userExists = Boolean(user); const enableAdmin = @@ -49,8 +61,18 @@ export default async function LocaleLayout({ enableSystem disableTransitionOnChange > - - {children} + + + {children} +