The ReviewPage is now a dynamic route,
meaning that this same component will be used
to render all the different review pages.
This also means that, if we
want to add a new review,
we can now simply create a new Markdown file.
Let's review the "hellblade" game for example.
I'll change all the front matter
properties accordingly.
Let's put 6 as the day,
and we already have a "hellblade.jpg"
image in the right folder.
As for the body, I'll just write
some placeholder text.
It's not our main focus right now.
So, we have a "hellblade.md" file.
This means that, if we go to our app,
and request the "/reviews/hellblade" path,
we'll see a page with the right
content straight away,
without having to modify any JavaScript code.
The ReviewPage component will automatically
load the data from the new Markdown file,
based on the URL path.
However, if we go to the Reviews page,
we won't see Hellblade in this list.
That's because, in the ReviewsPage component,
we only have two list items,
for Hollow Knight and Stardew Valley.
Now, we don't really want to
manually edit this file,
every time we add a new review.
Why don't we generate this list automatically?
In our "reviews.js" file,
we could add another function,
let's call it "getReviews" (plural).
And here we could return an array,
with all the items.
We'll implement this properly in a second,
but in the ReviewsPage we'll then
be able to call that new function
and get all the "reviews".
We need to use "await", because
getReviews is "async",
which means we also need to declare
this component function as "async".
That's ok, because this is a Server Component.
What I'll do for now is simply log the "reviews",
so we can check the data returned
by our new function.
Ok, if we save, we should see
that message in the logs.
"reviews" is currently an empty array, of course,
because that's what we're returning at the moment.
Now, let's think about how to implement
this function for real.
To find all the available reviews,
we could simply list the Markdown files
that are inside the "content/reviews" folder.
We can list the files in a folder
by using the "readdir" function
from the "fs" built-in module.
So, in "getReviews" we can obtain the "files"
by calling "readdir", which is asynchronous,
and passing the path, that is "./content/reviews".
Just to show you exactly what it returns,
I'll log the "files" variable to the console.
And if we save,
the page in the browser reloads automatically,
running our new code,
and you can see that "files" is an array
containing the name of each Markdown file.
We'll need to strip out the ".md" extension,
because what we want is the "slugs".
Let's transform this "files" array.
For a start, it's better if
we filter the elements,
and only keep the files that end
with the ".md" extension,
just in case there's some other
file in the same folder.
Once we're sure we only have Markdown files,
we can use the "map" method
to transform each element,
and we want to "slice" the file name,
to extract a substring,
containing the characters from zero,
that is the beginning,
up until the end but excluding the
length of the ".md" suffix.
You can pass a negative index
to count back from the end.
Let's log the "slugs" value now,
to check if our code is working.
You can see that this way
we correctly extract the slug from each file name.
Normally I would write unit tests
for this sort of code,
but for this example I'm basically testing
it manually with log statements.
Anyway, once we have the "slug"
we can get a full review object
simply by calling our existing
"getReview" function,
that will read each Markdown file,
extracting all the properties.
So, let's iterate over each "slug" in the array,
and for each one we can get
the full "review" object
by calling "getReview" passing
that "slug" as argument.
Note that we need to use "await"
because "getReview" is async.
Now, let's define a "reviews" array,
outside of the loop,
and we can then add each review to that array,
using the "push" method.
And finally, we can return the "reviews" array.
Let's see what happens now if we save.
There's a lot of data printed here.
The ReviewsPage is still logging
the data it receives,
and you can see that "reviews" is an array
where each element is an object with
"title", "date", "image", and "body" properties.
What we're missing here is the "slug".
We'll need that property in the ReviewsPage,
otherwise we cannot link to the right URL path.
Let's simply add the "slug" to the
object returned by "getReview".
And with this, each review should
have all the properties we need.
You could argue that,
in the ReviewsPage we don't
really need the "body",
so, as an optimization, we
could exclude that field.
But we would still need to read
each Markdown file anyway,
to extract the properties from the front matter,
so we might as well leave this code as it is.
And this is how we can automatically
get all the reviews.
The next step is to display that data in our page,
but we'll do that in the next video.