Skip to content

Commit

Permalink
Merge pull request #1199 from prezly/feature/care-6533-add-tag-page-t…
Browse files Browse the repository at this point in the history
…o-bea

[CARE-6533] Add Tag page to Bea
  • Loading branch information
fgyimah authored Nov 5, 2024
2 parents 8e2f681 + 139b591 commit 27b2b36
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 26 deletions.
1 change: 1 addition & 0 deletions adapters/server/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function configureAppRouter() {
return Router.create({
index: route('/(:localeSlug)', '/:localeCode'),
category: route('(/:localeSlug)/category/:slug', '/:localeCode/category/:slug'),
tag: route('(/:localeSlug)/tag/:tag', '/:localeCode/tag/:tag'),
media: route('(/:localeSlug)/media', '/:localeCode/media'),
mediaGallery: route('(/:localeSlug)/media/album/:uuid', '/:localeCode/media/album/:uuid'),
search: route('(/:localeSlug)/search', '/:localeCode/search'),
Expand Down
42 changes: 42 additions & 0 deletions app/[localeCode]/tag/[tag]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Locale } from '@prezly/theme-kit-nextjs';
import type { Metadata } from 'next';

import { app, generatePageMetadata, routing } from '@/adapters/server';
import { Tag as TagIndexPage } from '@/modules/Tag';
import { getStoryListPageSize, parsePreviewSearchParams } from 'utils';

interface Props {
params: {
localeCode: Locale.Code;
tag: NonNullable<string>;
};
searchParams: Record<string, string>;
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { generateUrl } = await routing();
const { localeCode, tag } = params;

return generatePageMetadata({
locale: localeCode,
title: tag.charAt(0).toUpperCase() + tag.slice(1),
generateUrl: (locale) => generateUrl('tag', { localeCode: locale, tag }),
});
}

export default async function TagPage({ params, searchParams }: Props) {
const themeSettings = await app().themeSettings();
const settings = parsePreviewSearchParams(searchParams, themeSettings);

return (
<TagIndexPage
locale={params.localeCode}
tag={params.tag}
layout={settings.layout}
pageSize={getStoryListPageSize(settings.layout)}
showDate={settings.show_date}
showSubtitle={settings.show_subtitle}
storyCardVariant={settings.story_card_variant}
/>
);
}
2 changes: 2 additions & 0 deletions app/api/stories/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ export async function GET(request: NextRequest) {
const limit = parseNumber(params.get('limit')) ?? DEFAULT_LIMIT;
const locale = params.get('locale') as Locale.Code | null;
const categoryId = parseNumber(params.get('category'));
const tag = params.get('tag');

const { stories, pagination } = await app().stories({
offset,
limit,
category: categoryId ? { id: categoryId } : undefined,
locale: locale ? { code: locale } : undefined,
tags: tag ? [tag] : undefined,
});

return NextResponse.json({ data: stories, total: pagination.matched_records_number });
Expand Down
31 changes: 22 additions & 9 deletions modules/InfiniteStories/InfiniteStories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import styles from './InfiniteStories.module.scss';
type Props = {
categories?: Category[];
category?: Pick<Category, 'id'>;
tag?: string;
excludedStoryUuids?: Story['uuid'][];
fullWidthFeaturedStory?: boolean;
initialStories: ListStory[];
Expand All @@ -30,25 +31,29 @@ type Props = {
total: number;
};

function fetchStories(
localeCode: Locale.Code,
offset: number,
limit: number,
category: Props['category'],
excludedStoryUuids: Story['uuid'][] | undefined,
) {
function fetchStories(props: {
localeCode: Locale.Code;
offset: number;
limit: number;
category: Props['category'];
excludedStoryUuids: Story['uuid'][] | undefined;
tag: Props['tag'];
}) {
const { localeCode, offset, limit, category, excludedStoryUuids, tag } = props;
return http.get<{ data: ListStory[]; total: number }>('/api/stories', {
limit,
offset,
locale: localeCode,
category: category?.id,
query: excludedStoryUuids && JSON.stringify({ uuid: { $nin: excludedStoryUuids } }),
tag,
});
}

export function InfiniteStories({
categories,
category,
tag,
excludedStoryUuids,
fullWidthFeaturedStory = false,
initialStories,
Expand All @@ -64,8 +69,16 @@ export function InfiniteStories({
const locale = useLocale();
const { load, loading, data, done } = useInfiniteLoading(
useCallback(
(offset) => fetchStories(locale, offset, pageSize, category, excludedStoryUuids),
[category, excludedStoryUuids, locale, pageSize],
(offset) =>
fetchStories({
localeCode: locale,
offset,
limit: pageSize,
category,
excludedStoryUuids,
tag,
}),
[category, excludedStoryUuids, locale, pageSize, tag],
),
{ data: initialStories, total },
);
Expand Down
5 changes: 5 additions & 0 deletions modules/Tag/Tag.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.pageTitle {
> h1 {
text-transform: capitalize;
}
}
56 changes: 56 additions & 0 deletions modules/Tag/Tag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Locale } from '@prezly/theme-kit-nextjs';

import { app } from '@/adapters/server';
import { PageTitle } from '@/components/PageTitle';
import type { ThemeSettings } from 'theme-settings';

import { InfiniteStories } from '../InfiniteStories';

import styles from './Tag.module.scss';

interface Props {
tag: string;
locale: Locale.Code;
layout: ThemeSettings['layout'];
pageSize: number;
showDate: boolean;
showSubtitle: boolean;
storyCardVariant: ThemeSettings['story_card_variant'];
}

export async function Tag({
tag,
locale,
layout,
pageSize,
showDate,
showSubtitle,
storyCardVariant,
}: Props) {
const { stories, pagination } = await app().stories({
limit: pageSize,
locale: { code: locale },
tags: [tag],
});

const newsroom = await app().newsroom();
const languageSettings = await app().languageOrDefault(locale);

return (
<>
<PageTitle className={styles.pageTitle} title={tag} />
<InfiniteStories
tag={tag}
initialStories={stories}
isCategoryList
layout={layout}
newsroomName={languageSettings.company_information.name || newsroom.name}
pageSize={pageSize}
showDate={showDate}
showSubtitle={showSubtitle}
storyCardVariant={storyCardVariant}
total={pagination.matched_records_number}
/>
</>
);
}
1 change: 1 addition & 0 deletions modules/Tag/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Tag } from './Tag';
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
31 changes: 16 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@prezly/content-renderer-react-js": "0.39.2",
"@prezly/sdk": "21.12.0",
"@prezly/story-content-format": "0.65.1",
"@prezly/theme-kit-nextjs": "9.7.2",
"@prezly/theme-kit-nextjs": "9.8.1",
"@prezly/uploadcare": "2.5.0",
"@prezly/uploadcare-image": "0.3.2",
"@react-hookz/web": "14.7.1",
Expand Down

0 comments on commit 27b2b36

Please sign in to comment.