Reputation: 592
Kind of losing my mind on this one. In my Next Js app I keep hitting this error of Error: Route "/api/materials/[materialId]" used
params.materialId.
params should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
I have a page.tsx
"use client";
import { type DataTableColumn } from "@/components/data-table";
import { BackButton } from "@/components/ui/back-button";
import { DetailsView } from "@/components/ui/details-view";
import { Inventory, Material } from "@/types/types";
import { notFound, useRouter } from "next/navigation";
import { use, useEffect, useState } from "react";
// Example form fields for a Material
// Adapt these to match your Material schema
const materialFields = [
{ key: "type", label: "Type", type: "text", required: true },
{ key: "color", label: "Color", type: "text" },
{ key: "colorCode", label: "Color Code", type: "text" },
{ key: "brand", label: "Brand", type: "text" },
{ key: "quantity", label: "Quantity", type: "number" },
{ key: "unit", label: "Unit", type: "text" },
{ key: "costPerUnit", label: "Cost Per Unit", type: "number" },
{ key: "currency", label: "Currency", type: "text" },
{ key: "location", label: "Location", type: "text" },
{ key: "Properties", label: "Properties", type: "textarea" },
];
// Fetch the material from the API:
async function fetchMaterial(materialId: string) {
try {
const response = await fetch(`/api/materials/${materialId}`);
if (response.status === 404) {
notFound();
}
const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching material:", error);
throw error;
}
}
export default function MaterialPage({
params,
}: {
params: Promise<{ materialId: string }>;
}) {
const router = useRouter();
const resolvedParams = use(params); // Resolve the promise for the 'materialId'
const [material, setMaterial] = useState<Material | null>(null);
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
// Load material when the page mounts or materialId changes
useEffect(() => {
fetchMaterial(resolvedParams.materialId).then(setMaterial);
}, [resolvedParams.materialId]);
if (!material) {
return <div>Loading...</div>;
}
// Prepare detail items for <DetailsView>
console.log(material);
const detailItems = [
{
label: "Brand",
value: material.brand, // Make sure this is a string
key: "brand",
editable: true,
},
{
label: "Type",
value: material.type, // Make sure this is a string
key: "type",
editable: true,
},
{
label: "Cost Per Unit",
value: material.defaultCostPerUnit, // This should be a number
key: "costPerUnit",
type: "number",
editable: true,
},
];
// -- Column definitions --
const inventoryColumns: DataTableColumn<Inventory>[] = [
{
header: "Quantity",
accessorKey: "quantity",
cell: (inventory) => `${inventory.quantity} ${inventory.unit}`,
},
{ header: "Location", accessorKey: "location" },
];
const productsColumns: DataTableColumn<Inventory>[] = [
{
header: "Model",
accessorKey: "name",
cell: (product) => `${product.product.name}`,
},
{
header: "Season",
accessorKey: "season",
cell: (product) => `${product.product.season}`,
},
];
// Called after a successful PATCH (edit):
const handleSaveSuccess = (updatedMaterial: Material) => {
setMaterial(updatedMaterial);
setIsEditDialogOpen(false);
};
// Called when the user clicks Delete
const handleDelete = async (id: string) => {
try {
const response = await fetch(`/api/materials/${id}`, {
method: "DELETE",
});
if (!response.ok) {
throw new Error("Failed to delete material");
}
// Go back to the materials list
router.push("/inventory/materials");
router.refresh();
} catch (error) {
console.error("Error deleting material:", error);
}
};
return (
<>
{/* Page Header */}
<div className="space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">
{material.colorCode} - {material.color}
</h1>
<div className="flex gap-2">
{/* <button
onClick={() => setIsEditDialogOpen(true)}
className="px-4 py-2 bg-black text-white rounded-md hover:bg-gray-800"
>
Edit
</button> */}
<BackButton />
</div>
</div>
<DetailsView
title=""
items={detailItems}
apiEndpoint="/api/materials"
itemId={material.id}
/>
</div>
</>
);
}
and my route.ts
// app/api/materials/[materialId]/route.ts
import { prisma } from "@/lib/prisma";
import { NextResponse } from "next/server";
//
// GET /api/materials/[materialId]
//
export async function GET(
request: Request,
context: { params: { materialId: string } }
) {
try {
// Destructure materialId from context.params
const { materialId } = context.params;
// No request.json() for GET — remove that part entirely
console.log("GET request for material:", materialId);
const material = await prisma.material.findUnique({
where: {
id: materialId,
},
include: {
inventory: {
include: {
movements: true,
},
},
products: {
include: {
product: true,
},
},
},
});
if (!material) {
return NextResponse.json(
{ error: "Material not found" },
{ status: 404 }
);
}
return NextResponse.json(material);
} catch (error) {
console.error("Error fetching material:", error);
return NextResponse.json(
{ error: "Error fetching material" },
{ status: 500 }
);
}
}
and I can't understand why I get this error consistently every time I load the page.
Upvotes: 0
Views: 503
Reputation: 1
Step 1: npx @next/codemod@latest next-async-request-api --force
Step 2: 'On which files or directory should the codemods be applied?': '.'
Also we need to make sure that the function is declared as async, otherwise the changes won't take effect.
Upvotes: 0