Redirecting Homepage Route0:07
All right, so I think in the last episode we actually made pretty good progress. So now I wanna take the User's profile or their feed, and I wanna make that a reality and get this rendered on the page. Let's get going. So I will start within my routes file and yeah, here's the homepage. That was just our demo, uh, for now that's gonna load that splash page, uh, the marketing page, but I can't tell if Jeremy implemented that.
that splash page, uh, the marketing page, but I can't tell if Jeremy implemented that. I'm pretty sure Simon worked on that. Right? But I don't see it here, so we might save that for the end of the video or maybe we'll pass it back to Jeremy or Simon's implement. So with that in mind, for the time being, let's just do, uh, an instant redirect to save us some time. Redirect, uh, homepage to home, and I believe home. Yeah, this is, uh,
Redirect, uh, homepage to home, and I believe home. Yeah, this is, uh, what I imagine is your default feed, right? Uh, like visiting x.com. And this does require authentication. So that's going to redirect us to the route with the name of login. Of course, in real life this is gonna be your login form, but for now they are just spiking in, basically, um, they're gonna instantly find a User and log them in.
Seeding Demo Data1:08
but for now they are just spiking in, basically, um, they're gonna instantly find a User and log them in. However, at this point, I don't think we even have a User, so let's try this out. If I were to dd the User, I have a suspicion that I'm gonna get null, come back and I do. Yeah. So what I'm hoping here is that, um, Jeremy set up a database seeder so that I, so that I instantly have some, um, data and followers and reposts, uh, that I can work with.
that I instantly have some, um, data and followers and reposts, uh, that I can work with. I really hope I have that. So let's go into database.php, database.c. Oh, okay. And yes, we do have that. Very good. So let's see real quick. We create 20 profiles, and then for each of the profiles, we make posts. So posts belong to profile. Remember, I'm learning this on the spot. So a post belongs to a profile. That's right post profile.
Remember, I'm learning this on the spot. So a Post belongs to a Profile. That's right Post Profile. Okay. And a Profile belongs to a User. Got it. And then for the Profiles, we do some followers. Uh, and then for all of the Profiles, we do some likes and then some reposts. Okay, I got it. So I should be able to run php artisan db:seed. And there we go. So now with any luck, if I switch back to the browser, give it a refresh, now we do have a User.
So now with any luck, if I switch back to the browser, give it a refresh, now we do have a User. Perfect. Okay, so let's do this. Close that out, return to our routes file, remove that, and now, yeah, we should be signed in. And then we redirect to the home route. The home route loads, the PostController, the PostController grabs the User's profile. And real quick, let's just return that profile and we should see Jason and we do Cool.
Reviewing Timeline Query2:42
And real quick, let's just return that profile and we should see Jason and we do Cool. So a profile consists of your display name, your handle, a bio, and some images. Perfect. Okay. So next it looks like Jeremy is using, uh, query classes, which is fine. We have a TimelineQuery for viewer. So let's see how this works. So for a viewer, it creates a new query.
So let's see how this works. So for a viewer, it creates a new query. Okay? It's like a static constructor. And then he calls get, all right? And that returns a query, which would be this right here. So it fetches posts, loads the profile, adds, um, some exists checked, okay, this is fine. Okay, so now, yeah, it's returning a Blade view, but of course it's now going to return an Inertia page feel.
Switching to Inertia Page3:30
Okay, so now, yeah, it's returning a Blade view, but of course it's now going to return an Inertia page feel. So we can use the helper inertia function, or if you wanna use the facade directly, you could say inertia, render, exact same thing. Okay, so now let's just use the convention of post/index, and then I'm gonna create that. So we would come down, and again, I'm just gonna show you this workflow a couple times within here, resources/js/pages.
and again, I'm just gonna show you this workflow a couple times within here, resources/js/pages. Let's create our new file posts/index.blade.php. Okay? So you'll remember, welcome shows us the general approach, right? We need to import the layout, and then we can have our code, or I'll paste this in and I'll say, postIndexView, this is my sanity check. Let's come back, give it a refresh and fail to resolve import layout.
Let's come back, give it a refresh and fail to resolve import layout. Okay? So we can use relative or we can set up an alias within v config. Let's see if we have it. Nope. Um, we could alternatively set up an alias here so that you can do things like, um, @layouts. And that would always refer to your JS roots. Uh, some people like that, and some people are big fans of always just using the relative path.
Uh, some people like that, and some people are big fans of always just using the relative path. Um, be explicit. They would say it's whatever you want. So now if I come back, sure enough, this is the post index view, okay? So at this point, I'm just gonna migrate everything over. I'm gonna go to the Blade view. I'm gonna grab all of that. I'm gonna move it over. And wherever I encounter, uh, php code or conditionals, I will migrate it over wherever I encounter Blade components.
PHP code or conditionals, I will migrate it over wherever I encounter Blade components that are being referenced, I will create new view components to match those. Okay, let's go into post/index. So this is the blade view. He's referencing the layout. Then there's content, there's a post form, there's a feed. Real quick, let me run blade on this. Okay, not too bad. So I'm gonna take everything here, hide the sidebar, switch back, and I'm gonna paste it in here.
So I'm gonna take everything here, hide the sidebar, switch back, and I'm gonna paste it in here. Or, or actually maybe we can swap out the wrapper. Diviv, let's see what that looks like. So of course, remember you can't just do a copy and paste if I come back. Yeah, so actually this is more than I would expect, but sure enough you can see that, uh, things like this, of course, they are not being evaluated and, and compiled. Good. So let's get going. We have, this is all static.
Migrating PostForm Component5:49
of course, they are not being evaluated and, and compiled. Good. So let's get going. We have, this is all static. I'm just looking for non-static stuff. All right, this delegates to a PostForm Blade component. Once again, I'm gonna run Blade on this, okay, a lot here. I would probably wanna clean this up. So in the sidebar, within the components directory right here, why don't we add a new file called post-form.blade.php.
within the components directory right here, why don't we add a new file called postForm? All right? So template, and I'll paste all of that in reformat. And this is what we have these SVGs, I don't know what they are. I'm gonna extract those into their own, uh, components. It looks like it's expecting a profile here and using some routes that we will need to, uh, handle. So at the very top, I'm gonna do script setup.
and using some routes that we will need to, uh, handle. So at the very top, I'm gonna do script setup. And I'm gonna say, uh, in order for this to work, I need access to a profile for now. So again, if we were using typescript, I might say like, this should be, uh, up type, profile, resource or something like that. But in our case, we're not gonna do that. It's just an object. Okay, so now here's what I can do. I can just go through every reference
It's just an object. Okay, so now here's what I can do. I can just go through every reference of the profile PHP object and replace it with the JavaScript version. So for example, with the alts, uh, attribute, I could say, all right, let's bind to this and we will use template strings. And then it looks like profileDisplayName. So this will then become profileDisplayName, just like that makes sense.
So this will then become profileDisplayName, just like that makes sense. So yeah, I can do the same thing here. imageSource will be profile, doAvatar, URL. All right. And then it looks like we'll do one more together for the textArea. This will be, uh, what's up, profileHandle. Okay, so I think that's mostly it. I still wanna clean up this file.
Okay, so I think that's mostly it. I still wanna clean up this file and extract some of these components. Uh, but nonetheless, that looks okay. So let's switch back. And this is our index view. So now this can be swapped out with our post form. And now don't forget though, post form expects a profile. So I need to send that through profile and I'm going to assume that we have some kind of profile that is passed to this view.
and I'm going to assume that we have some kind of Profile that is passed to this view. We can return to PostController to confirm that right here, we send through the profile and the posts, which would mean within this view, we're going to accept the profile and the posts. Alright? And again, I just wanna remind you, we're being pretty loose here. We're just saying gimme any kind of object, whatever it is, whatever shape it comes, we're going to accept it.
We're just saying gimme any kind of object, whatever it is, whatever shape it comes, we're going to accept it and just assume it's in the correct shape. Uh, depending upon where you come from, that's probably okay, or you might think absolutely not. We don't get any auto completion. You need to migrate to TypeScript. Fair enough, uh, if you think that, but for this series, it's just a bit too much to cover. Alright, so now if I scroll down,
but for this series, it's just a bit too much to cover. Alright, so now if I scroll down, we're sending through the profile. Alright, next post, postForm. Uh, I wish we would just normalize those. If it's, if it needs clarity that it's a post prompt, then maybe the component itself should be PostPrompt. But I think postForm is enough. So if I come back, yeah, I can see that there. Uh, but I do see this lingering csrf directive.
So if I come back, yeah, I can see that there. Uh, but I do see this lingering CSRF directive. Okay, we will need to update that. So where do we have it? Yeah, we're gonna swap that out once we actually make this interactive. For now, we're, we're, we're creating the views and we're creating the markup. Uh, but we're not yet making it dynamic and we're not making these forms functional. Okay? So if I come back, there we go. Now it's removed.
Migrating Post Feed Components9:26
and we're not making these forms functional. Okay? So if I come back, there we go. Now it's removed. Okay, so next, let's just keep going. We return to our index view and it looks like we're looping over posts and rendering a Post component. So I would go to the post blade component. I would copy this and I would move it to a new view component. So this time, one more time, I'll do it from the sidebar,
to a new view component. So this time, one more time, I'll do it from the sidebar, but then the components directory, we can add a new post view file and then paste that in. And remember, we're gonna have to now go through this file and update it. So let's see how quickly I can do it. And I'll see if I can skip ahead to save ourselves some time. So in order for this to work, it needs access
to save ourselves some time. So in order for this to work, it needs access to the post object mostly. All right? I will define that script and then define the props. And we need a post. All right? So keep in mind any of these route references we're gonna handle, uh, possibly in the next episode actually when we pull in wayfinder. So we will keep those as awkward strings, um, for now.
we pull in wayfinder. So we will keep those as awkward strings, um, for now. Alright, so now this becomes postProfileAvatarUrl. This one becomes avatarFour, postProfileDisplayName. I think that's right. And yeah, I'm not gonna make you watch this, you don't need to. I'm gonna fast forward and do the exact same migration for every single reference that you see here. Alright, so I've mostly taken care of that.
for every single reference that you see here. Alright, so I've mostly taken care of that. If you take a look, yeah, notice I've updated it here and here, here, and not everything though, I wanna do some of this with you, but here and here and here, all right, saves us some time. Okay, so now if I scroll back up, let's talk about this real quick. So there's a Blade or a php conditional that says if the Post is a repost
So there's a Blade or a php conditional that says if the Post is a repost and we have content, then render this same component again. But this time we're gonna render the repost. Okay? So, and it also looks like there's a showEngagement prop that we should accept. So let's do that now. showEngagement, not even entirely sure what that is right now, but that's okay. All right, so we reformat
that is right now, but that's okay. All right, so we reformat and then showEngagement is a boolean that defaults to true. And then once again, the showReplies is a boolean and defaults to false. All right, so now let's scroll back down. We can update this. Now this is gonna load the current post form. It's gonna send through the post, which would be post repost of, and then showEngagement is gonna be set to false.
It's gonna send through the post, which would be post repost of, and then show engagement is gonna be set to false. Next here. Yeah, we, we have to convert this into an expression. So maybe we could say if post. And yeah, at this point we know we're gonna pass through some kind of, um, json resource. Maybe I just have a little helper, boolean that is, isRepost, something like that. Uh, if we go into Jeremy's Post model isRepost,
is repost, something like that. Uh, if we go into Jeremy's Post model repost, that's just checking if this is, um, truthy. So maybe I'll start with that, and then later we could, we could possibly add a, a helper property and then maybe postContent. Yeah, something like that. All right, let's keep going. So next we have a conditional if showEngagement, I would just replace this, the if showEngagement, and now I can get rid of that.
I would just replace this, the if showEngagement, and now I can get rid of that. And then that cleans it up just a little bit. Next, it looks like we have, um, three buttons or three components. A LikeButton, a ReplyButton, and a RepostButton. LikeButton. And this is a button that contains, okay, um, let's migrate this over. Once again, within components, let's create a new one LikeButton.
Once again, within components, let's create a new one like button. So yeah, generally when I'm doing these migrations, I'm not thinking about like, oh, I need to change this or refactor it. I'm really trying to do a one-to-one, uh, migration. And then later I could do a second pass where I, where I look over it and say, okay, can we clean this up? But I generally, I try not to do both at the same time. Uh, because there's just so many moving pieces here.
But I generally, I try not to do both at the same time. Uh, because there's just so many moving pieces here and so much, so much, uh, php code that needs to be migrated to JavaScript expressions. There's a lot here. Okay, so anyways, here's our template. Let's now, and a split go into the like button blade component. You grab that and we paste it in. Next we find out whatever it requires. It looks like we have an active variable.
Next we find out whatever it requires. It looks like we have an active variable and account, okay, define props. Uh, active is gonna be a Boolean. And actually let's do this. active will be a Boolean with a default of false. And then we'll have a count will be a number with a default of zero, presumably. All right, so here we have some classes.
with a default of zero, presumably. All right, so here we have some classes. Let's do this class and we'll say, are we active and we want hover, textPixel, and then textPixel as well. I think I, I think that's right. Okay, otherwise nothing. Or I can use the object syntax. Next we have an SVG, and then we have another one here. So I'm just gonna grab all of this, come down and paste it in. All right, next, this will be our count.
come down and paste it in. All right, next, this will be our count. Okay, so let's switch back and I'll show you this. This will now be our like button next for reply button and repost button. It's gonna be the exact same process. You don't need to watch it. Let's skip ahead. Alright, so now through the magic of screen casting, uh, we've advanced the clock by about five or 10 minutes. And if you take a look, we now have dedicated view
we've advanced the clock by about five or 10 minutes. And if you take a look, we now have dedicated view components for a like button reply, button repose again and again, just take a look at these pretty simple stuff. So it's overly complex just because of these SVGs that we're going to extract. Also, notice that the comments are redundant, so I would remove those entirely. Next, we have the exact same thing for these little buttons, remove those.
Next, we have the exact same thing for these little buttons, remove those. And next we have a commented out reply form. We're gonna keep that commented because that's how it was given to us. And we'll take a look at what needs to be done there, uh, in the future. Next we have if showReplies. So we'll say if showReplies. Now we don't need that conditional.
So we'll say v-if show replies. Now we don't need that conditional and it looks like we loop over the replies so we can say v-for reply in post.replies. Now we don't need that and this is gonna delegate to a ReplyComponent. So I assume a Reply is distinct from the Post itself and it has its own shape. So this is one that I have not migrated over.
and it has its own shape. So this is one that I have not migrated over. Let's do this one together, up to the components directory, reply, view, paste that in. And now it looks like we need a post object. And then once again, showEngagement and showReply. So this seems pretty similar to the PostView component, so we'll see how they are different. But for now, I think I can steal a lot of this. If I have a script set up, I can paste this in.
But for, for now, I think I can steal a lot of this. If I have a script set up, I can paste this in and yeah, I think that would be fine. Alright, so next, once again, uh, magica screen casting. We're gonna update all of these old php object references to our new Post, uh, JavaScript object. Alright, and I think that's done. So again, I'll let you take a look. Don't forget we are ignoring hres entirely for now, but we have all of the updates here and here and here.
Don't forget we are ignoring hres entirely for now, but we have all of the updates here and here and here. Here's the post content. Here's where we swap out the php conditional with a V. If we are referencing all of those same view components. And then, um, if we are showing replies, and I'm curious how many levels we can, we can nest replies to replies. Uh, but for now I think, I think that's okay. So we're just gonna go back up a level now.
Uh, but for now I think, I think that's okay. So we're just gonna go back up a level now and this can be swapped out. And actually you can see here, yeah, this is what I was talking about. This is very similar to what we're doing in Reply. So I'm curious, can I just reuse this? And at some point can I merge those two components entirely? Let's see if showReplies, loop over them. Yeah, this is seemingly the same thing.
Let's see if showReplies, loop over them. Yeah, this is seemingly the same thing so I can save ourselves some time like, so I think that's right. So with any luck, this took a little bit of effort, but this is 95% done other than the, uh, the hfs. All right, so now we go up a level again, let's go back to our PageComponent for viewing posts and we'll just see what else needs to be done. This is static. We have a PostForm.
and we'll just see what else needs to be done. This is static. We have a PostForm component, we have a feed. So again, we have a v-for here that can now just turn into a v-for item and posts. We should key them. I think we have a itemId and now I can get rid of that php. And with any luck, I think that's all migrated over. So let's switch back to the browser and see how we're doing.
Debugging Render Errors18:45
And with any luck, I think that's all migrated over. So let's switch back to the browser and see how we're doing. Alright, and I'm not seeing any posts. That's okay. This is what you should expect. There's so many steps here and you're gonna miss a few. So at this point, you'd open up dev tools, go to your console and figure out, okay, it looks like it's accessing some, uh, php item object that we didn't spot. And where's this happening?
that we didn't spot. And where's this happening? It looks like on the page component. So if I were to come back, do we have any reference to item? Yes, we do. We forgot to update this. Okay, so we have a lot of references to this. So let's pull that in and then the post will be the item. All right, let's switch back, cross our fingers. And even worse, we have a blank screen entirely. All right, let's keep going. Folks, uh, cannot read property
And even worse, we have a blank screen entirely. All right, let's keep going. Folks, uh, cannot read property of undefined reading profile within post view on line 19, post view line 19. Okay? So at some point it's trying to read profile, but that is null. Uh, so we're trying to access properties on null, and now we have to figure out, well, how is that possible? So let's just go through it. This is our post view.
and now we have to figure out, well, how is that possible? So let's just go through it. This is our post view. I have a feeling it was related to repost 'cause we kind of guessed how to access that. So let's, here's what I do. Sometimes I just do omission and see if, see if omitting the thing, fixes the thing. So now if I come back and refresh, yes, okay, I had a feeling it was gonna be related to that. Uh, and here's why. You'll see
I had a feeling it was gonna be related to that. Uh, and here's why. You'll see that we are rendering another Post. So a Post that quotes another Post. Um, and I just had a feeling this is probably something like null, which meant on post, actually that's this current file. Then we're trying to access profile on null, and that's what's triggering the error. Okay? Fair enough. So now we just have
and that's what's triggering the error. Okay? Fair enough. So now we just have to figure out what the issue is. Um, and yeah, I I'm just not entirely sure how we access this. So here's what I might do. I'm just gonna return the post collection so that I can take a look at exactly what's being passed to Inertia. Uh, of course I can also pull in the view dev tools, uh,
passed to inertia. Uh, of course I can also pull in the view dev tools, uh, extension, and I'll show you that in just a minute. But for each one repost of, oh, I know what it is. Okay, so it's declared as an underscore, so it could be null if it's not a repost. Let's just take a look here. Do we have any examples of where it's an object? Yes. So in some cases we will have a Post that is a repost.
Do we have any examples of where it's an object? Yes. So in some cases we will have a Post that is a repost of another Post, and in those cases we need to render what is being reposted. Okay, I think, I think I understand this. So if I switch back, come to Post, it is not, um, it is not repost of it is repost of, and if that could be null, I wonder, can I just check to see, is that truthy?
and if that could be null, I wonder, can I just check to see, is that truthy? I think let's go back and there we go. Okay, so now let's find a Post so I can show you. Do we have any? I know we do. There we go. Here's one. So yeah, check it out. This is a Post that is a repost of another Post. So yeah, I'm, I'm sure you saw this when you were watching section two with Jeremy. But yeah, just to make sure we're all on the same page.
were watching section two with Jeremy. But yeah, just to make sure we're all on the same page. This is the component for a Post, but within it, if it is a repost, uh, where is it? Where are you, where are you? Right here? If it's a repost, then we render the same component again. And in those cases we don't show engagement. Okay, so now I'm starting to understand it a little better, but there's no two ways about it. There's just a lot of steps involved in this.
but there's no two ways about it. There's just a lot of steps involved in this. So if you, you are considering migrating, um, a legacy application of yours to an SBA, you can do it. Just be prepared. It's a little bit cumbersome. Uh, perhaps AI can help us to some extent, but there's just a lot of steps. There's no two ways about it. All right, so we're gonna keep chipping away at this. I think we made some decent progress. Uh, in this episode.
All right, so we're gonna keep chipping away at this. I think we made some decent progress. Uh, in this episode. I next wanna take care of integrating Wayfinder so that we can have these URLs wired up properly. And then we need to implement, um, the functionality itself so that I can click on this to like a Post. I can click on this to comment on a Post. The backend functionality is there. Jeremy already wrote that. So now we just need to wire up the forms.
Jeremy already wrote that. So now we just need to wire up the forms and I'll show you how.
