fix: await searchParams and params for Next.js 15 async API, compute totalPages in all-users page
Some checks failed
lint / lint (push) Has been cancelled
test / unit (push) Has been cancelled
test / integration (push) Has been cancelled
lint / lint (pull_request) Failing after 9m41s
test / unit (pull_request) Successful in 16m33s
test / integration (pull_request) Failing after 17m3s

This commit is contained in:
2026-05-14 17:28:35 +02:00
parent 12adddaa16
commit b95cebc799
9 changed files with 44 additions and 23 deletions

29
.env
View File

@@ -1,10 +1,27 @@
POSTGRES_USER=thoughts_user POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres POSTGRES_PASSWORD=postgres
POSTGRES_DB=thoughts_db POSTGRES_DB=thoughts
HOST=0.0.0.0 HOST=0.0.0.0
PORT=8000 PORT=8000
DATABASE_URL="postgresql://thoughts_user:postgres@database/thoughts_db" DATABASE_URL="postgresql://postgres:postgres@localhost:5432/thoughts"
PREFORK=1 JWT_SECRET=secret
AUTH_SECRET=secret
BASE_URL=http://0.0.0.0 # Public base URL — used for ActivityPub actor URLs and canonical links
BASE_URL=http://localhost:8000
# CORS — comma-separated allowed origins, or * for permissive (default: *)
CORS_ORIGINS=*
# CORS_ORIGINS=https://your-nextjs-app.example.com
# Rate limiting — max requests per minute per IP (disabled by default)
# RATE_LIMIT=60
ALLOW_REGISTRATION=true # set to false to disable new sign-ups
RUST_ENV=development # set to "production" to disable AP debug mode
# NATS event bus (optional — federation and notifications still work without it,
# but events will not be delivered to the worker)
NATS_URL=nats://localhost:4222
# Logging
RUST_LOG=info

View File

@@ -29,12 +29,13 @@ import { redirect } from "next/navigation";
export default async function Home({ export default async function Home({
searchParams, searchParams,
}: { }: {
searchParams: { page?: string }; searchParams: Promise<{ page?: string }>;
}) { }) {
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const resolvedSearchParams = await searchParams;
if (token) { if (token) {
return <FeedPage token={token} searchParams={searchParams} />; return <FeedPage token={token} searchParams={resolvedSearchParams} />;
} else { } else {
return <LandingPage />; return <LandingPage />;
} }

View File

@@ -5,11 +5,12 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ThoughtList } from "@/components/thought-list"; import { ThoughtList } from "@/components/thought-list";
interface SearchPageProps { interface SearchPageProps {
searchParams: { q?: string }; searchParams: Promise<{ q?: string }>;
} }
export default async function SearchPage({ searchParams }: SearchPageProps) { export default async function SearchPage({ searchParams }: SearchPageProps) {
const query = searchParams.q || ""; const { q } = await searchParams;
const query = q || "";
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
if (!query) { if (!query) {

View File

@@ -7,11 +7,11 @@ import { notFound } from "next/navigation";
import { Hash } from "lucide-react"; import { Hash } from "lucide-react";
interface TagPageProps { interface TagPageProps {
params: { tagName: string }; params: Promise<{ tagName: string }>;
} }
export default async function TagPage({ params }: TagPageProps) { export default async function TagPage({ params }: TagPageProps) {
const { tagName } = params; const { tagName } = await params;
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const [thoughtsResult, meResult] = await Promise.allSettled([ const [thoughtsResult, meResult] = await Promise.allSettled([

View File

@@ -11,7 +11,7 @@ import { ThoughtThread } from "@/components/thought-thread";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
interface ThoughtPageProps { interface ThoughtPageProps {
params: { thoughtId: string }; params: Promise<{ thoughtId: string }>;
} }
function collectAuthors(thread: ThoughtThreadType): string[] { function collectAuthors(thread: ThoughtThreadType): string[] {
@@ -23,7 +23,7 @@ function collectAuthors(thread: ThoughtThreadType): string[] {
} }
export default async function ThoughtPage({ params }: ThoughtPageProps) { export default async function ThoughtPage({ params }: ThoughtPageProps) {
const { thoughtId } = params; const { thoughtId } = await params;
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const [threadResult, meResult] = await Promise.allSettled([ const [threadResult, meResult] = await Promise.allSettled([

View File

@@ -4,11 +4,11 @@ import { getFollowersList } from "@/lib/api";
import { UserListCard } from "@/components/user-list-card"; import { UserListCard } from "@/components/user-list-card";
interface FollowersPageProps { interface FollowersPageProps {
params: { username: string }; params: Promise<{ username: string }>;
} }
export default async function FollowersPage({ params }: FollowersPageProps) { export default async function FollowersPage({ params }: FollowersPageProps) {
const { username } = params; const { username } = await params;
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const followersData = await getFollowersList(username, token).catch( const followersData = await getFollowersList(username, token).catch(

View File

@@ -4,11 +4,11 @@ import { getFollowingList } from "@/lib/api";
import { UserListCard } from "@/components/user-list-card"; import { UserListCard } from "@/components/user-list-card";
interface FollowingPageProps { interface FollowingPageProps {
params: { username: string }; params: Promise<{ username: string }>;
} }
export default async function FollowingPage({ params }: FollowingPageProps) { export default async function FollowingPage({ params }: FollowingPageProps) {
const { username } = params; const { username } = await params;
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const followingData = await getFollowingList(username, token).catch( const followingData = await getFollowingList(username, token).catch(

View File

@@ -21,11 +21,11 @@ import { Button } from "@/components/ui/button";
import Link from "next/link"; import Link from "next/link";
interface ProfilePageProps { interface ProfilePageProps {
params: { username: string }; params: Promise<{ username: string }>;
} }
export default async function ProfilePage({ params }: ProfilePageProps) { export default async function ProfilePage({ params }: ProfilePageProps) {
const { username } = params; const { username } = await params;
const token = (await cookies()).get("auth_token")?.value ?? null; const token = (await cookies()).get("auth_token")?.value ?? null;
const userProfilePromise = getUserProfile(username, token); const userProfilePromise = getUserProfile(username, token);

View File

@@ -11,9 +11,10 @@ import {
export default async function AllUsersPage({ export default async function AllUsersPage({
searchParams, searchParams,
}: { }: {
searchParams: { page?: string }; searchParams: Promise<{ page?: string }>;
}) { }) {
const page = parseInt(searchParams.page ?? "1", 10); const { page: pageStr } = await searchParams;
const page = parseInt(pageStr ?? "1", 10);
const usersData = await getAllUsers(page).catch(() => null); const usersData = await getAllUsers(page).catch(() => null);
if (!usersData) { if (!usersData) {
@@ -27,7 +28,8 @@ export default async function AllUsersPage({
); );
} }
const { items, totalPages } = usersData; const { items, total, perPage } = usersData;
const totalPages = Math.ceil(total / perPage);
return ( return (
<div className="container mx-auto max-w-2xl p-4 sm:p-6"> <div className="container mx-auto max-w-2xl p-4 sm:p-6">