Building an email client with the Next.js App Router & Postgres

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so today I've been building an email client with nextjs and postgress and I want to walk through the demo and show some cool things in the code so I have my app open here I've got my inbox and you can see clicking between Everything feels really fast and that's because we want to take advantage of caching as much as possible so I have an inbox sent mails you know some different folders as well too when I'm looking in my inbox I can click on an individual email for any given folder if I want I can make a new email so let's say I want to make this to Lee and testing hello I'll send this and then it revalidates all the data and we see it redirect here and pop this open and I can delete this as well if I want to so that's just a quick run through but I want to talk through some of the interesting bits here and walk through the code kind of step by step and talk about uh how I built this it was actually really fun so let me start with the uh the entry I started with create next app just built a completely fresh create next app scaffolded Tailwind scaffolded out pmpm and set up my configuration pretty basic app and then I actually went to v0 so I started in v0 and it got me pretty far after only seven uh iterations on my initial prompt so I was prompting basically a three column layout folders on the left in the middle the current list of emails inside of the folder and then on the right the actual viewing of the email so this helped me get a good start with my Tailwind code so I took that and again I had scaffolded out this config scaffold out a basic next config and then in my root layout I'm basically just wrapping the application setting up some dark mode Styles installing a font nothing too wild here so let's first look at the Shell so the the shell of a folder you see this email empty view so when I click on a folder there's no email selected and I'm basically showing nothing here but then the layout for this has a folder column that's an async component so this is a server component an email column that grabs the pram from the URL and then the children now this is going to be important in a second when we talk about scroll position um so what this means is that everything on this page is part of this shared layout except for this right third most column so when I click for example on Lee bell.com just this bit on the right just this third column is actually part of a different route so f for folder slash name slash ID and then we have this page and this is the specific bit of UI that's rendered as a child of just that layout so for example one of the cool things that this enables is if I pull this up here here and I'm scrolling down I click on John do notice how the scroll position doesn't reset between these because the layout doesn't render even though we're updating the UI and we're getting new information and this was basically all I had to do originally this was rendering when I wasn't using a layout lifted it up to the layout done it's all you need to do so that's a nice little UI touch there um let's talk about this specific page so inside of this page we're grabbing the email that's inside of this folder given the folder name and the email ID uh we render this toolbar and then we render the individual contents of the email so what does this look like getting the email well I'm using forell postgress so it's basically just vanilla postgress I'm actually not even using an RM I'm just doing um SQL through tag template literals here so I can uh use any values I want to pass in like the folder name and the email ID with also making sure those are stand Iz to prevent against SQL injections so I you know get all the emails in my folder here and I return it back and that's basically all this part is and we have moved the data fetching down into the actual component and the page at this level so if we go back up to the layout well how do we get all of these different emails for example how do we get all the emails in the folder well there's this email list column this is the second column and inside here we have a very similar thing get emails for folder we pass in the folder name we iterate over all of the different emails and then this is just jsx basically going in here kind of looks similar the only thing that's different is there's a conditional check if we're in the scent folder versus the you any of the other folders sents kind of a special folder now I realized as I was going over this I probably need to also have a better join here to have both the Cent email as well as the recipient email but we can get to that in a future iteration um so that's that and one of the nice things here is that because caching is built into the nextus app router I don't really have to do anything and by default all of this is going to be cached now the nice thing about this is for my email client in this instance it feels really fast when I'm clicking around and you can imagine that when I get new email I would have essentially have an API that that email server could hit to revalidate the data and show a new email so let me show what the revalidation process looks like by starting to talk about what the form looks like so I click the email and this redirects us to this sent SL new route that has a form so this is also using that same shared layout so just this third column is being rendered the other part of the layout comes from the layout file and and inside of here we're doing a couple things uh one we're getting all the email addresses which I'll show in a second which again know just SQL um and then we have a form and the form takes a server action and inside this form we have who you're sending it to the subject and some information now you're going to notice a couple things here one as I start typing I get a type ahead here a combo box that allows me to use the keyboard and navigate between the components I want and critically this is aware of all of the emails in my database but I could also type some new email at gmail.com and it's still an input so I'm still able to use this value and really big shout out to react Arya components here for making this super easy to do um it was pretty simple actually to get set up to take the values I fetched on the server and then pass them in as items in the list box component and then kind of style this with Tailwind to match the look that I had going in the application so that was actually really easy to do which is nice so I can let's say pick one here I can write a subject my subject but actually one thing that's interesting is this has both client and server side validation so if I try to submit right now it's going to say this field is required because I've added the proper required field on the HTML element but we can say my subject we can say this is a test now I could go click the button in the top right but another fun thing I added was command enter to actually submit the form and this was a fun one basically I just have the text area but then on key down I'm looking for specifically doing the The Meta key or the command key command enter and then this one took me a bit to figure out but on the on the events I'm calling up to the form not in this component and then I'm saying you know what actually produce a submit event because if you produce a submit event much like this button here that has a type of submit that's actually going to submit the form so there's three inputs in this form there is the um there's the person you're sending it to there's the subject and there's the body and when I submit the form I'm able to actually go over call This Server action and then I validate that input on the server as well too using Zod now this is just a demo so I've kind of hardcoded me as the logged in user here with the sender ID of one um and I haven't uh worked with transactions in a while so that was fun but with postgress I'm able to start my transaction run a bunch of different queries in here based on the way that my data is structured so it basically looks like this user users can send and receive emails they can have multiple folders folders can have multiple emails and then an email can also be in multiple folders so we've got a nice relational database going here that makes this pretty easy to set up so when I'm adding in new information I got to for example get the recipient ID if it doesn't exist I got to put that user in the database basically I insert a new email I get the ID of the scent folder I add the new email into the scent folder and then I if everything went great I can commit this transaction if for some reason something didn't go great I can roll it back and then I can roll back all of these commands at once and then if successful I do two things here one is I revalidate all of the data on my page I could get more granular with this if I wanted to but since I'm doing multiple queries here if I for example added a new email into the set folder that needs to update the data in this component it also needs to update this badge on the left so I could use C tags in this instance I just revalidated all data uh and then I actually redirect to the newly created email as well too and I'm able to get the newly created ID back from my uh SQL query so I can redirect to that now a cool thing about server actions you might have noticed there was no client Side Event handlers here so this is actually not dependent on JavaScript so if I go over here let's say I want to close that uh let me disable JavaScript and let's say we want this to go to now you'll notice when I type Lee it's not going to give me that nice dropdown before because we don't actually have that available so this is new email test.com and sub my subject new email and we'll submit and you'll notice there was the browser loading spinner here because I had to go to the server and still works even though there's no JavaScript and we see everything get updated as we would expect so that's really nice I love to see the progressive enhancement here I'll go ahead and enable JavaScript I also want to I guess I can briefly mention kind of how the code base is structured so I opted for the throw everything in the app folder because you can uh because you can coate f collocate files I said you know what we're just going to dump everything in here so not only do I have all of my components in here some of these fetch data some of these don't um I have my actions my server actions which is sending an email and then deleting an email as well too um I have all the different queries and the types for those queries inside of here um a couple small utilities just for formatting but I've just decided to put it all inside of here um as well as just SVG icons that I've grabbed as well too yeah so that's that's pretty much the application it was really fun to click around and build this and kind of show some of these patterns like maintaining scroll position and Progressive enhancement and uh really it was a lot of fun to work with especially starting from B zero so hopefully this was interesting let me know if you'd like to see more content like this but uh yeah peace
Info
Channel: Lee Robinson
Views: 38,164
Rating: undefined out of 5
Keywords:
Id: mpcE5rxgLxM
Channel Id: undefined
Length: 12min 22sec (742 seconds)
Published: Sun Nov 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.