Files
myeasycms-v2/apps/web/app/[locale]/(marketing)/changelog/page.tsx
Giancarlo Buomprisco 7ebff31475 Next.js Supabase V3 (#463)
Version 3 of the kit:
- Radix UI replaced with Base UI (using the Shadcn UI patterns)
- next-intl replaces react-i18next
- enhanceAction deprecated; usage moved to next-safe-action
- main layout now wrapped with [locale] path segment
- Teams only mode
- Layout updates
- Zod v4
- Next.js 16.2
- Typescript 6
- All other dependencies updated
- Removed deprecated Edge CSRF
- Dynamic Github Action runner
2026-03-24 13:40:38 +08:00

119 lines
3.2 KiB
TypeScript

import { cache } from 'react';
import type { Metadata } from 'next';
import { getLocale, getTranslations } from 'next-intl/server';
import { createCmsClient } from '@kit/cms';
import { getLogger } from '@kit/shared/logger';
import { If } from '@kit/ui/if';
import { Trans } from '@kit/ui/trans';
import { SitePageHeader } from '../_components/site-page-header';
import { ChangelogEntry } from './_components/changelog-entry';
import { ChangelogPagination } from './_components/changelog-pagination';
interface ChangelogPageProps {
searchParams: Promise<{ page?: string }>;
}
const CHANGELOG_ENTRIES_PER_PAGE = 50;
export const generateMetadata = async (
props: ChangelogPageProps,
): Promise<Metadata> => {
const t = await getTranslations('marketing');
const resolvedLanguage = await getLocale();
const searchParams = await props.searchParams;
const limit = CHANGELOG_ENTRIES_PER_PAGE;
const page = searchParams.page ? parseInt(searchParams.page) : 0;
const offset = page * limit;
const { total } = await getContentItems(resolvedLanguage, limit, offset);
return {
title: t('changelog'),
description: t('changelogSubtitle'),
pagination: {
previous: page > 0 ? `/changelog?page=${page - 1}` : undefined,
next: offset + limit < total ? `/changelog?page=${page + 1}` : undefined,
},
};
};
const getContentItems = cache(
async (language: string | undefined, limit: number, offset: number) => {
const client = await createCmsClient();
const logger = await getLogger();
try {
return await client.getContentItems({
collection: 'changelog',
limit,
offset,
content: false,
language,
sortBy: 'publishedAt',
sortDirection: 'desc',
});
} catch (error) {
logger.error({ error }, 'Failed to load changelog entries');
return { total: 0, items: [] };
}
},
);
async function ChangelogPage(props: ChangelogPageProps) {
const t = await getTranslations('marketing');
const language = await getLocale();
const searchParams = await props.searchParams;
const limit = CHANGELOG_ENTRIES_PER_PAGE;
const page = searchParams.page ? parseInt(searchParams.page) : 0;
const offset = page * limit;
const { total, items: entries } = await getContentItems(
language,
limit,
offset,
);
return (
<>
<SitePageHeader
title={t('changelog')}
subtitle={t('changelogSubtitle')}
/>
<div className="container flex max-w-4xl flex-col space-y-12 py-12">
<If
condition={entries.length > 0}
fallback={<Trans i18nKey="marketing.noChangelogEntries" />}
>
<div className="space-y-0">
{entries.map((entry, index) => {
return (
<ChangelogEntry
key={entry.id}
entry={entry}
highlight={index === 0}
/>
);
})}
</div>
<ChangelogPagination
currentPage={page}
canGoToNextPage={offset + limit < total}
canGoToPreviousPage={page > 0}
/>
</If>
</div>
</>
);
}
export default ChangelogPage;