A second version of this course released using Next 13+, but this course is great if you want to see another example fullstack project. We now recommend you take the Build a Fullstack App with Next.js, v2 course.

Check out a free preview of the full Build a Fullstack Music App with Next.js course:
The "Song UI & Time format" Lesson is part of the full, Build a Fullstack Music App with Next.js course featured in this preview video. Here's what you'd learn in this lesson:

Scott demonstrates inserting song data into the songs table, including song number, title, date added, and song duration. The formatting functions used to format date added and song duration into appropriate time formats are built using the Format Duration library. Student questions regarding if getServerSideProps has to be named exactly that and if edge functions compared to lambda functions are expensive to hold on a live CDN

Get Unlimited Access Now

Transcript from the "Song UI & Time format" Lesson

>> What's next is we need to have these rows here. Each row has the number of the song where it is in the playlist. Looks like a picture of the song, the title of the song, the artist that created the song, album we won't have when it was added in a time ago format, okay?

[00:00:20] And then how long the song is, in a duration clock format, minutes, seconds. So, that's what we'll do, so let's get started with that. So in order to do that, we are going to have to use the table body after the table head. So we'll say Tbody, that, And then inside the table body, we'll just map over the songs.

[00:00:47] We'll say songs.map, we'll get a song, and we'll do some song stuff. So for each one of these songs, we're gonna make a Tr, which is a table row. All right, so we'll say table row, like that. And then I think by default, can we add a border or not?

[00:01:10] No, I think that's the Td, we're to figure that out. But regardless, I want the table row to highlight when you hover over it. So what I'm gonna do is I'm gonna use this SX property that allows me to add custom styles. And I can say, first, I wanna add a nice transition, so I'll say transition.

[00:01:27] I don't know, 0.3 seconds. All, so all 0.3 seconds to transition all properties 0.3 seconds. And then what I'll say is and on hover, I want the background to just be slightly lighter than what it is now, and it's transparent now. So I'm just gonna make it slightly more transparent, basically.

[00:01:56] So I want the background to be RGBA 255, 255, 255, 0.1 in this case, where it was initially 0.2, so slightly more transparent. It'll be subtle but it'll be enough to know that you're hovering over it. Okay, because this is a map, we have to add a key property that'll be song.id.

[00:02:22] This thing's freaking out cuz I put it in too early, hold on, back out of that, there we go. And then, I wanna make sure the cursor is a pointer. So it shows the finger that you can click on it, otherwise you won't know that you can click on it.

[00:02:38] So I'll put cursor. So that's our table row. And then in between the table row, we're going to add basically for each single column, which is a Td, we're gonna add the theme for the song. So the first one will be the number, so the index basically, where in the playlist this thing is.

[00:03:09] That'll just be the index + 1. So I need to get the index here, I'll say i, and this will just be i + 1. And again, that's this number we're getting on the left. So the 0 thing in the array is at 1, so I'm adding plus 1 everything cuz it starts with 0, and I don't wanna put 0 here.

[00:03:30] So we got that. And the next thing is another Td. And this one is gonna be for the name. So this will be song.name here. The next one is when it was created at, so we'll add another Td. This will be song.createdA t. And the last one that we're gonna add will be another Td, and this one will be on the duration.

[00:04:02] So this will be song.duration. So we got all of those. I haven't passed in the songs obviously, so, yeah, need to pass in the songs. Let me just do that, right, quick on a song table, back inside of our playlists, [id].tsx. Let's just pass in the songs, right, quick from playlist.song.

[00:04:28] So I'll say songs is playlists.songs. Satisfy that songs requirement. And then we should be able to go back. And now it's saying objects are not valid as react elements. That mean I'm trying to render an object somewhere, or it's the date. Yeah, you got a toString right quick.

[00:04:55] So, we're gonna make a format for this, we haven't gotten there but yeah, toString. Cool, so here we go. Got a nice playlist with our very descriptive data added, just in case you really wanna know the exact millisecond the song was added, and what time zone. You can see it, if you're into that.

[00:05:14] But yeah, you can see the scrolling looks. Pretty nice that how the gradients stays put, kinda like a parallax effect, almost. And yeah, it all looks pretty cool. So, there's obviously some formatting issues we have here. We need to format this date added, that's just not gonna fly.

[00:05:35] And what does this number mean for duration? I don't know, is that how many seconds it is, or days? I don't know, so we need to format that so it doesn't look like whatever that is. I think everything else looks really nice. I know there's supposed to be images here, but our songs don't have images.

[00:05:50] I tried to, I mean, just finding the songs it's hard. Finding the images is even harder. So with these placeholder images we want, but I figured we just skip it for now. And as far as these formatters, what we're gonna do is, we need to make one that formats the dates, we make one that formats the time.

[00:06:06] And if we look at the the design, the date is formatted and what I call time ago format. So it's like one minute ago, whatever ago, we could do that. There's literally so many of those out there. I think there's actually one called time ago that does that.

[00:06:23] I'm just gonna format it in the actual date that doesn't. So I think Spotify actually does both. I remember seeing it somewhere where it was like, it'll say time ago, up until a week. And then we'll put the date of like. If it's within a week, it'll say three days ago, four days ago, five days ago.

[00:06:40] But anything after seven days ago, like this date, December 12, 2021. So we're just gonna do that. We're just gonna put the date there. So that'll be our formatter. And then the next one, what we'll do here is gonna be the formatter for the time. So it actually shows you this, a clock, right?

[00:06:58] So 2 minutes and 27 seconds, 2 minutes and 22 seconds. So we'll do that. And the duration that we have for each song, is actually the time in seconds, and not minutes. So we already have that. So let's make these formatters. We'll go to our lib folder, we'll make a new file here, we'll call them formatters.ts, and we'll make some.

[00:07:20] Luckily for us, I already had u install a sweet package called format duration, so you can import that. And then we'll make a function called formatTime. And this one's gonna take in a time in seconds. And I'm just gonna default to 0 just in case. And then all it's literally gonna do is this return format, duration, which will be whatever the time in seconds that you had, times 1,000 milliseconds.

[00:08:06] And then for the date, we'll just say this one's pretty easy. We'll say formatDate. This one's just gonna take in a date object, so literally a date object. And it's just gonna return date.toLocaleDateString. And we'll put an en-US as the first argument, and the second argument, we'll just say, this is how we wanna format it.

[00:08:33] I want the year to be numeric, I want the month to be a long month, so we'll give them a long month, spell it out. And then day, I want to be numeric. So this will return a string in this format. Okay, so now we head back to our songs table, and we can format these.

[00:09:07] So song that created that, I don't need the toString any more, I can just actually use formats, dates. And put the created add in there, and then for duration, I can say formatTime. I can put that in there, and then save it. And it hopefully did the auto import for me, yeah, it did.

[00:09:35] I love when it does that, cuz it doesn't do it all the time. And there we go, we got a nice duration and we got a nice time. Maybe a short time will be better, let's do a short time. I don't like the long time that I'm looking at it, I kinda hate it now.

[00:09:51] [LAUGH] Let's do, is it short, or what do you want? Yeah, I guess it's short. Let's try that. Yeah, yeah, that's better, short is definitely better. Okay, so now we got our playlists from our database. Every playlist has the same amount of songs. So if you're like, why is it not changing?

[00:10:15] When we see that the database, we gave every playlist all the songs in the database. So they all have the same songs. So that's why it looks like they're not changing, but they just happen to have the same data. If you want some variation and you can mix the array of songs or not add all the songs.

[00:10:31] He's got to write a more advanced seed script. I didn't wanna put you through that. So we didn't do that. But there we go, we got our playlists, we got a song, we got to formatter. And the only thing that is left is the thing that's still ugly on the page, and that's the player, at the bottom.

[00:10:48] It's just there waiting for you, waiting to be created, save for last. And then for the player, there's a lot that's involved with it, because up until this point, we haven't had to worry about global state on the client side. Well, now we do. Because now the player which is part of the layout that sits in the app, the _app component needs to be aware of what playlist we're playing, what song is playing, that's coming from a playlist page.

[00:11:15] So we need to find a way to have some global state. So we'll get into global state. It won't be Redux. So if you're thinking like, he goes through that, we're not doing Redux. It's not happening. I think Redux is great, but this is overkill for this. There's a lot of ways to do it.

[00:11:29] I'll talk about that. And then, there's gonna be a lot of animation stuff, and obviously, music stuff. And there's actually some really, I would say high level bugs and issues that we're gonna run into, and I'll talk about how to solve that. Things that I've seen companies just get crippled at, that some really advanced React stuff, something I had to study that was really tough for me.

[00:11:53] So, I'll talk about that and we'll get past those issues, and then we'll deploy this thing, yeah?
>> When we were doing your rating functions that would run on the server side of the component.
>> We always put get at the beginning and then, do you want to use that exact function name?

>> Get server side props? Yeah, you have to. Next is looking for this function. There's two other ones, there's getStaticPaths, and this one is for generating, this is like if you were generating a static website. How does next JS know what routes to make? So to have to return an object of routes.

[00:12:34] Here are all the routes that I want you to generate. And then the other one is getStaticProps, which works with getStaticPaths. And this will literally do the same things, getServerSideProps but only at build time, and not at runtime on the server.
>> Could you speak to the cost of edge functions versus lambda functions, are they expensive to build live on a CDN?

>> No, they are actually still pretty cheap. And it also depends on what platform you deploy to. So with Vercel, it's all just abstracted away from you. You just kind of just pay them a fee and they just handle it all. I mean, at the end of the day, it's literally fractions of a penny.

[00:13:12] Whether it's a Lambda or Lambda@Edge, it's still relatively gonna be cheaper than hosting a server that's always running. Because you're only getting charge for your usage. And usually, the usage is measured in thousands of calls. That's when you start looking at dollars, like okay, after a few thousand calls, we're looking at dollars now.

[00:13:35] So it's relatively cheap, because it's cheap for the providers to actually host, right? It's cheap for them. They don't have to maintain active servers anymore. They can share their resources a lot better. They can get more customers with less equipment. So they share some of that cost by not charging you as much, I assume.

[00:13:55] So yeah, it's still relatively cheap, even compared to servers.