Business Card Application - Next.js, Prisma, Tailwindcss and Next Auth - Full Stack Application

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi everyone hope you're doing well today we're going to be building an application we're going to be doing authentication we're going to be using prisman to interact with our database and we're going to be styling until when css the application itself you're going to be able to log into it and give your personal details and then it's going to deploy almost a little website for every single person that signs up and they'll be able to share this link and it will it will have all their contact information on it so the website is relatively simple however some of the concepts are important and i think once you get the concepts of this down when we move on to our next application which is going to be significantly more complex then this is a really good basis so to get started what i've done is i've run the command where's that so mpx create next app with the example flag we're using the with tailwind css example and i've called it business card now i'm going to try and explain things um quite in depth a few people have mentioned that um you know sometimes i might do things pretty quickly without explaining so i'm sorry i don't intend to um we're going to be using prisma to interact with our database we're going to be using tail and css for styling sorry prisma is this one to interact with the database and next author for authentication and honestly things like next off it makes full stack development possible um you know going back a few years doing authentication was complex and a massive task in itself and to create something that's secure you you know really need to do a lot of research whereas with next auth you will see it is really quite simple so the first thing i'm going to do we are going to be using um typescript in this one of the cool things about prisma is that it's fully typed and you will see that as we go but i'm just going to do some typescript setup stuff with nextgs um i don't really need to do this but we can so the first thing to do is i am going to change these to tsx files as opposed to js um we don't need this hello i can get rid of everything in men and everything in footer i'm going to create a dot prettier rc and a eslint ic.js like this and then i'm going to copy this and paste it in so this is just the setup that i use for pretty much every project and i think it's a good it's a good practice to get into so make sure if people are working within your project then these settings will apply to them as well um the blog post has a few more things on about doing um pre-commit checks i didn't install husky though as you saw um and then let's grab this and drop in like so and then if we do our npm run dev now everything should be set up and what i'm actually gonna do is reload this window so it pulls in the um eslint and prettier sounds and it will form everything how we want it to now it's gonna say i don't know why that's not working but there we go why are you not liking that what we need cool so that's our basic setup done the next thing we're going to do is get next all set up so i'm not going to use the version 4 it's still in better i'm going to use v3 so i'll just click the v3 docs here let's choose the prisma adapter and then we're going to follow some basic boilerplate code to do authentication now one of the things that makes authentication within a full stack app complicated is authenticating your front end and your back end normally you will have a server setup for your api um you know going back quite a few years i would use an express server for my api and you know you're passing your passing tokens you're configuring cookies you're doing all sorts of stuff like that and it does get quite complicated um however you will see this setup is just amazing um so next auth works on both the front end client side and server side and then also on the on the server side when i say on the front end client side and server side i mean you would use it in something like get server side props um of course it's actually happening on the server so we've done that let's make our authentication route so this route in api if we make a new folder called auth and then we're going to make a route called dot dot next auth like so dot t s and this um square brackets dot dot this is a catch all route um i don't know what's going on with this okay cool that is format another thing i'm going to do is i'm going to use google um so if you i'm doing this off screen so if you go to console.cloud.org yeah console.com.google.com yeah and you need to go to on the top left menu the little hamburger menu if you click that and then go to sorry something's um something's happening there's not meant to the navigation isn't actually working come on don't do this to me now hmm the navigation is just not working at all okay there we go so hover over apis and services hit credentials and then i already have the um oauth id set up i'm just going to use some ones i've used previously but there's create credentials right at the top and you want to create a auth client id so let's make a dot eng file um and you can see we're using google client id and a google client secret like so and that's just the plugin i've got those hiding keys on there it says me worrying about that you can see it's got some white space there so hopefully that's the right one um we will soon know if it's not so past in your id and your secret and now we're going to do the prisma stuff so if we do prisma init and actually let's just an mpm install next auth that's um it's gonna be a good start and then i will bring this browser back over now and what i want to do is get this set up so in our prisma folder we've got a schema so we're going to do sqlite as the database and then for the url we just do file and then db.db and in the schema prisma folder that's going to make a dv dot db like so and then let's um let's paste all this because this is a weird schema file why is that not for mine these need to be all on new lines and things like that because it's a schema file and the formatting is important so bear with me i need to do this it won't it won't actually the time default now data user relation fields references is unique so the session model oops so you may have to do this as well if you copy it if not then that's good sessions almost there okay cool so that is almost so let me just bring this in here so what i want to do now is mpx prisma migrate dev and what's happening now is basically we have an sqlite database and within sql database if you're familiar with you know nosql databases you don't really need to define too much of what is in there you can create a model almost and just give it any data that you want um but that isn't the case with a sql database so we create the tables [Music] and we need to do that in advance so that's essentially what this schema is doing it's defining our tables within our database and then also the relations um so we've got an accounts table this is a field it's a string um and it's required these ones are the question mark that means it's not required so you define your schema and then we'll run a migration and that migration is going to actually perform the sql and um change the the structure of the database so right now with the airbus it's not anything it's empty so when we do this it's going to actually create these tables within the database for us to interact with so one of the other great things about prisma is it's properly typed and whenever we're using any of the models we can we can use the types that prisma generates for us so that's really good and the auto completion you get on the front end is really nice along with knowing that you are using the right fields and field names so that is that's pretty much done so the next thing for us to do is actually implement it on the front end so let's actually did i even run the dev server yeah we do because we've got our typescript so you get this error sometimes if you're on windows and you're using and you're running migrations with prisma it basically just means that you need to delete this folder and try again so everything looks good i'm just waiting for this to load right now so we don't need this or this this doesn't look good it's a blank page oh yeah maybe it does we delete everything do we so let's put some of this code in so the first thing we need to do is add the provider and we do that just by copying and pasting it this is the wrong place i don't know why it's out of those so we've got our provider and what that does is it means we can use this use session this use session hook so now on our index page i'm going to pretty much copy this cured i will talk through it in a second let's drop that there wow there's lots of those again don't need those oh this loading and that is our authentication pretty much done so next auth gives us a sign in a sign out method and also use session hook um we're taking the session from that you session hook and that use session hook we need this provider configured so we can use that hook all over our application so now that that is done on our home page is telling us hey you are not signed in so let's sign in we're going to sign in with google let's see if it worked i don't use those emails i don't really care if they're seen so yeah that is working then we can sign out and let's try signing back in so our authentication is working that is great and you can see we've configured that in you know 15 minutes so that is brilliant now i'm not really going to use it like this i want to do server side authentication and this is on the client side and to be totally honest it's not strictly necessary to do a server side and client-side for this application would work just fine excuse me this would work absolutely fine to do it on the server side and just keep it like this but actually i want to do some some more data fetching and it's just going to be easier if i do it on the server side and what we could do is so if i wanted to do this on the client side what i would do is i would use um a hook called use swr and basically you can do conditional fetching so i'd say like you know if there's a session then go ahead and try and fetch this user's information and it will fetch on the on the client side if there wasn't a session it wouldn't do that um but we're gonna do it on the server side so actually we don't need to um we don't need this provider i'm just gonna leave it there for now so let's um let's think about doing this on the server side so what i'm going to use is get old get session instead of view session so that's it two hooks for authentication that are provided so now i'm going to do export const get server side props that's going to take in context and i'll show you what that is and then we're gonna say const session equals away to get a session i'm gonna pass the context and then of course this needs to be asynchronous and then get server side props it needs to return something so we're going to return the props and let's just return the session for now and then of course we need to take in that session into our component and we should see the exact same result except it's happening on the server side so that's pretty cool we are up and running so let's um let's change this so let's call it business card application all right so i'm going to crack on doing some of the logic here the next thing i want to do is i'm going to say someone needs to be signed in to somebody to be signed in to actually create one of these business cards so actually when they are signed in what i want to know is like do they have a profile already and then because we need that profile information to to actually be shown so let's create a schema for that profile so call it model profile like so and then there's going to have an id let's just copy this actually and then what else do we want so we can have a name which is going to be a required string we're going to have an email which is a required string and that needs to be unique we're going to have a bio which is going to be a string that's going to be also required and then we can have a phone which is an optional string we'll have a twitter which is an optional string we'll have instagram which is an optional string in facebook which is an optional string i hate that for mine but i really i don't want to waste time getting it all nicely lined up so we got id name email bio so that's cool so now that we've added something to our schema in order for it to be reflected in our database the actual sql database what do we need to do we need to do a migration so we do mpx prisma migrate dev name other profile and then that migration is going to run it's generating our prisma client which you're going to see in use right now so one important thing to note is this gets server side props this is not happening on the front end um this is happening on the server side so what i'm going to do is i'm going to import prismaclient here's my client and yeah that's definitely not right like so and just because i'm important into this index page it doesn't mean it's shipped to the front end i'm only going to use it inside get server side props so i'm going to say it comes prisma equals new prismaclient like so and then what we can do what we can do is here so the first thing i want to do i'm going to say silicon's profile equals away it's prisma dot profile dot find unique and then we're gonna say where the email is gonna be the session.user.email like so because in our profile we have got a unique email address so we can we can use that find unique and then i want to return that profile as well like so just a little optimization we're seeing if there's a session and then we're returning the session but if there's not a session it's still going to try and make this request so what i'm going to do here i'm just going to say if there's not a session then i'm going to return and then we can return the props where the session is just going to be not so we'll return if there's no session then we'll return from we'll return at this point and then this code won't be executed so we will save a call to the database and this gets server-side props it's executed every single time um the page refreshes like this so let's get our dev up and running again so our profile right now is probably going to be console.log profile so then let's just have a look let's refresh the page and you can see this is coming as null and that's because there's no profile so you can see profile is now like that because there isn't a profile so then what we want to do is if there is not a profile we need the user to create a profile so inside of here let's just say if there is not a profile then we want to show a component like create profile so let's go and create that component so i'm going to create a components folder components like so create profile this is going to be a component so let's export default function create profile returning div for the h1 create your profile now okay and then inside of here we can say create profile and that's all i've imported here and of course we need to bring in profile into that component so as expected we don't have a profile so we're getting the option create your profile now [Music] so yeah one thing to note is everything is been centered right now which is fine so the full height of the screen um yeah that's fine so create your profile now we're gonna we're gonna crack on with some of the logic and then we'll do the styling in a little bit okay so inside create profile we want a form to update these fields so to do the form um i am going to install react hook farm and i'm also going to install axios to make the network requests you don't need axios you can use fetch um i've i've used axios for a lot yes and that's what i'm used to so i am going to keep using it but you don't have to you can use fetch so and again react hook farm is another awesome um [Music] another awesome hook that is it just makes doing forms so much easier um so i'm going to import use form from react hook farm i want to import axios from axios and then from that use form hook i want to take the register and handle submit equals use form like so and then inside of here actually i'm going to create that function so on submit form which has taken in values i just want to come to like those values for now and then yes i do want that div but i also want to form we're not giving an action we're giving it on submit now we're going to handle submit which is the method we've taken from the react hook um from the use form hook and we're going to give that our function on something form like so and then let's work in an input like this so the name is going to be actually name we don't need an id on this one and then to register this field we do register and then we give it the name of the field and then i'm actually going to make this required as true so that was a lot um a lot of stuff that we've just done so we are using this hook and the hook is giving us a register function and a handle submit function the handle submit we're using as the on submit and we're passing it our function on submit form so the handle submit is going to manage the submission of the form um but what we actually do when it's submitted is inside this function this register is literally we're using this to give react hook from the fields the inputs that we wanted to track so if we look now we're not showing this right oh yeah here we go so if i add a placeholder to this equals enter your name um i'm good okay enter your name and then let's add a few class classes uh oh does that so class names so let's do it full width uh bg gray 100 text gray 900 rounded medium height of 12. 2xl mxl cool so padding left of two is gonna give a bit of padding on that placeholder so that's awesome i'm gonna copy this down now um four times and then actually we want to do a text area as well i'm going to give it the same class names i want to register it like this this is going to be bio we can self-close the text area like that then placeholder how about you a little bit about you and then of course let's um imagine top three okay looks pretty dull but i don't mind and we can add a rows property to the text area so we can make it like rows equals four i think why is that working rose does anyone like this i i don't know okay so this one is going to be uh so we've got the name the bio so let's look at our schema so we got the name email is going to come from the user model so phone twitter instagram and then facebook so let's get this done so we got phone phone to your phone number but this is not actually required on any of those twitter instagram oh twitter and to your twitter twitter link facebook ntr facebook link and then instagram instagram and to your instagram link okay so this is looking pretty amazing on that text area i know why it's not working actually it's because we've defined the height there we go and i heard that background being like that so bg grey 50 i don't know if we need to go like no let's just leave it as a hundred it is fine yeah what else so the name bio required to the rest are optional we've got a phone to our facebook and insta let's add in a button so the type is going to be a submit button and then let's add some classes to make this a button so if we do background indigo 700 text white rounded medium so add some pattern on the left and right add some padding on the top and bottom a little bit less we can do a hover property so make it just go a little bit lighter background indigo 600 and let's put some match on the top that looks like a button to me perfect and then we might want to add a title it's the h1 create your profile and then we can do like text to excel fun semi-bold text gray 900 something like that create your profile perfect so let's see if it works so we should be getting a console log so we've got a name by your phone twitter facebook instagram then by our phone to our facebook instagram so that is all working now it's not that useful to console like those values um what we actually want to do is submit the values and do something with them so we're going to create an api route called create profile dot ts and basically inside of the nexus api route this is a when it's deployed this is going to be a serverless function um but you need to export a default function export default function um that's going to be an export default async function which got the request the response like this so i can add to response 200 i want to send back the profile that we create um so let's have a look at what we need to bring in so we need to bring in import get session from next auth i think that's client we also need import prismaclient from that's at press my client so we can do const oh comes prisma equals a new prismaclient like so i say a concession equals a way to get a session that takes in the request like that then we can say if there's no session when we want to return response uh yeah response.status 401 if there is a session then what i want to do is const profile equals away prisma dot profile dot create so the data that we give it is going to come from the request body so we can destructure that from here we can say so we've got the name by your phone facebook twitter instagram so name by a phone twitter instagram facebook did i get all of those name by a phone facebook twitter instagram yeah equals the request.body and then that's going to be the data right there yeah so name bio oops nan bio phone facebook twitter instagram and then the user we need to connect let's just format that twitter user why is this not doing ah we haven't created the relationship have we that's why it's not working yeah so this um so each user has a profile which is a profile and it can be not there and then each profile has a user and then a user id which is an int like that um user which is uh let me have a look at the syntax for this i look this up literally every time i um every time i do this prisma schema relations that's what we want user relation so uh relation fields is user id what's the other one references there's the id yes that's a user fields profile user id and i use a relation fields user id reference as an id the relation scale used in the arts yeah so that's right so the user has a profile which is optional pass an attribute relation the type of the field user id in the model profile is not much in the type of the referenced field id in the model user oh it's a string strange well okay didn't realize that okay so that should be good now um so if you do mpx prisma migrate dev and give it a name added user relation let me just change this as soon as i have a uk keyboard but i've typed with the us one with the um columns of the ikea for so many years and pm dev i need to be able to switch so i can actually use the the pound sign um okay so this should be done now so then we can do user and then we want to connect the user where the email is going to be the session.user.email what are we missing email perfect so again i know i've done quite a lot here so let's talk through it so we take a request and a response into this function we are destructuring all of these fields that are coming through the request.body we're just about to configure this form to actually submit this data in the body we are checking if there is a session using this request object so if there's no session then we're returning a 401 status of not authorized if there is a session then we're checking to see well we're creating a profile like this route is literally only going to be called from this create profile component which is only going to be shown if there is a isn't a profile already so it comes profile equals the word prism.profile and then we're creating it this is the data that we're going to be creating in the profile and then we're connecting it to the user we're just saying this is the user that this profile belongs to and then we're returning a response of 200 if everything goes well and we're sending back the profile so hopefully that is um that's all good and what we could really do is wrap this whole thing in a in a try catch um so you could just do try catch like this see like all of this in the tri statement and then if there's an error you know you can return 500 um dots and error like that i just send that error in case something goes wrong okay so that looks good the api route so now we actually need to make that request to the api realm so like i said i'm going to be using axios and what i'm going to do is in this form function i'm going to say const config and that is going to be an axios request config so we can use that there it's imported here you can see um and basically we're going to pass this config to our to our request so let's make this async so then i want to say crown's response equals await pixels and then we have the config and then it just comes to like that response so this is actually making the request we're passing the config and then inside the config we're going to have a url which is simply going to be why has that changed back so we've got the url which is going to be forward slash api forward slash create profile we're going to send the data which is just going to be the values we're just sending the values we are going to send it by post like the method of post um that's important because if it's if you don't define that the default is obviously a get request and that doesn't have um a body so you can you can pass data in a get request and then we can define our headers so we say content type is application json and we should be good to go so this is the url we're passing in the data it's a post request um and we're just telling her that it's json so let's give it a try so name phone number twitter facebook link create profile something bad happened api create profile type res is not a function oh response dot status let's run stop status okay let's try again let's refresh get rid of that okay so it worked because we actually have a profile now um so let me show you something else pretty cool about prisma so i'm going to create a new um a new terminal window and if you're an mpx prisma studio this gives you a way to view what's in your database you know add stuff delete stuff so let me delete that profile records let's make sure so let's just come to like that profile here and then on the front end we're going to log in the response that's good so then let's try again so i'm going to refresh create profile so we can see we've got our response back we've got the bio email facebook id instagram name phone twitter user id and we've already got so we've got the profile which was no oh wait that shouldn't even execute where is that coming from ah great profile where is that coming from console.org profile okay i say because this chord shouldn't execute because it was returned so let's try that one more time i mean it's working you can see it's working just fine so let's delete that let's refresh let's create profile so it's doing some stuff we've got our response back profile logged on the back end this time so that's perfect now one thing that's happening here is because we are doing the profile fetch on the server side obviously there's no revalidation of this data happening like if we did it on the client side so what i'm going to do is essentially refresh the page when we make that submission well when we receive the response so to do that i'm going to import um use router from why does this keep something back from next router i would say accounts rather equals use router and then we will say if response.status equals to 200 router.reload like so so let's try that so we'll delete it we've got a profile now so it's not displaying refresh again and we don't let's create that profile wait for the response and it's refreshed so that is perfect so now what we need to work on is inside of our dashboard when we have a profile we're going to want to see that profile information and then maybe have a button so we could edit that profile but let's get the component done for displaying the information all right so at the moment where we don't have a profile then we're showing the create profile so we want to say if we do have a profile then we want to display a different component so i'm going to create that profile the displayprofile.tsx and then let's just export default function display profile like so and for now let's just return to dev and said this will display the profile and then we want to say here where there is a profile then display profile so now where we do have a profile so this will display the profile so what do we want to do for this profile we want to do kind of the same thing um so on this index page here we're going to be fetching the profile so we want to pass this profile to the component and it's saying here actually this isn't taken in profile so if we bring in this profile like so it's going to get rid of this error what we actually should do is declare the um declare the types for these props um we're not going to worry about that right now so we can take the profile let's console.log the profile on the front end so now we have got all of our profile information here so we maybe don't want to get the id or user id um so on the index page where we're doing our unique profile where this we can do a select and then we can say yep we want their email facebook instagram oh we got fun that's an iron their bio their name and their twitter all right do we do name twice email facebook instagram phone bio name and the twitter so we're just selecting those things so if we go back you can see let's refresh the page you can see now we're only getting the things that we're asking for so to get this information in the profile obviously we've got access to this profile props so let's just do inside of this h1 we can say profile dot nem and that's going to put the name on the page um inside some p tags we will say profile dot bio and you can see we're not getting type completion for this if we declared the props properly then we would be so then we've got the bio like so and then actually let's do an unordered list with some list items so then we'll do um profile dot twitter facebook instagram instagram [Music] and then at the top there we can do profile.email and then profile dot phone so that's cool we've got all that stuff and then we can do some styles to this class name let's do text gray 800 text watch um text left i think we should get rid of this stuff on here yeah that's better because we do max weights 2xl mxr so the class name on this let's do text to excel found vault and then the bio is cool we can actually because i kind of want to have the you know the head in here so then the class name we can do imagine bottom of 10. just separate those out a little bit and then you know let's do a margin top of 10 move that down so what we're gonna what we're gonna get is we're gonna get a you know a bit of a header for that stuff there so on the index page yeah we'll change that around afterwards so we've got our profile information display now um of course we want to be able to edit this now for simplicity what i'm actually going to do is create another component to edit the profile which is going to be really similar to the create profile we could actually modify this create profile to handle both editing and creation but for as simple as a to learn the basics let's create a new component so edit profile.tsx and what i'm going to do is i'm going to copy everything from this and there's just going to be a few small differences so in our use form we can pass in initial values right how do we do this it just changed around i think is it formstead like this let's have a look so i was um saying about react hook from the good documentation it has so let's um let's have a look so get started validation existing forms there hours each field is required validation existing form ui library schema code examples so on v7 so where is initial form state here default values so as i passing those in register handle submit our default values there we go default values like that so then this is going to be edit profile and it's going to take in a profile then the default values what we should be able to do is literally just give it the profile object and then that is all going to be the same but then we want to edit the profile use a different route to edit but it is going to be a post request so let's have a look at this it's on our index page we need to have a way of showing this edit profile situation so so let's do some simple ui stats so i'm going to do is i'm going to import use state from react and then let's make it state here so editing and set editing and that's going to be equal to false then if there's a profile and we're not editing then we're going to display the profile but then if we're a profile and we're editing then i want to display edit profile like so and then let's change this so we'll put in a fragment so if there's a profile and we're not editing then we're going to display this but then we're also going to have a button which on click is going to set editing to true so then edit profile and actually let's grab those button styles [Music] what's your class name equals that [Music] okay and then actually let's just put hammocks on that's not gonna work so let's make this into a div and then we can do let's flex it flex call justify center then the button let's do max width extra small or something like that why is that working there we go mixed with access mode actually it's small okay so edit profile so in the edit profile let's see edit your profile so that's good let's change the bio hi i'm adam reach out on overchat and then i don't know i don't want a facebook on there so edit and of course that isn't going to work because we didn't create that root yet so we got an arrow back so i'll change that to edit profile as well so in our api let's create a new file called edit profile dot ts and i'm going to copy all of this from create profile and then we want to update so i think we do an update we will say where um email is equal to session.user.email data email session.you said that email it's not my comma cool so we're taking all the stuff from the request body we've got the request if there's not a session then return um we're updating the profile where it matches this and connecting the user that's fine console login sending the profile back so let's give that a try something didn't happen request fill with dash code 500 edit profile api slash edit profile it goes away it's translated profile same than that so it looks good so let's refresh this edit profile hi my name is adam the biomes i think that is from the previous one and promised so if there is answers i think there are api slash edit profile we've got the values there method is post i've got everything we need up there bad with me so we're taking all of that stuff press my.profile.update the change you're trying to make or violate the required relation profile to user between the profile and using models so maybe we don't need that connect because it's already connected in theory so let's try that okay looks like it worked hi my name is adam so you'll just connect on the initial creation okay perfect so that is working and we're able to edit the profile so that is great so then the only thing we didn't really consider is how we're gonna display this on the front end so normally we would use like a slug and actually that's what we're gonna do we're gonna make a slug field and add that into to pretty much everywhere so this is interesting because it will allow us to go back and look at how we will change what we've already done how we can add add new stuff in so within our profile model let's add a slug which is going to be a string it's required and it's also got to be unique so we've added field so we need to run a migration so npx prisma migrate dev with the name flag of add slog2 profile now this is going to give us a one in flag i believe yeah because there is already rows in the table is what it's saying so let's refresh this i don't know if we have prisma studio still running no so let's do npx prisma studio okay how quick dies dismiss profile [Music] prisma profile find many the column does not exist in the current database select i think it's because of the failed migration okay so let's um yeah let's do because i can't load prisma studio now so let me just delete this database file [Music] and then let's make a new database file so definitely not recommended but let's run um well that same command so we do knew my question so by just deleting our database it's just the same thing as deleting that profile and user so we don't have any profiles yet um so let's refresh this we're probably going to need to log back in but we don't have the dev server running so npm run dev i know it's a generate our client as well i need to delete this next folder right now another way around it would have been to have made the slug optional by putting a question mark then create the field add a value into either just delete the whole profile that we've got already or add a value into that one that we've got there and then that would have worked as well to be able to run the migration properly but hey oh we figured it out so now we have that field what we're going to do is let's reload and make our profile again we need to add into the create profile underneath our name let's add another field for we'll call this like enter your unique profile url this is required and then that's going to be slug let's copy that over to the edit profile while we're here and then we're doing all of the values so that's going to work and we're also fetching all the values so that's good you don't need to add it there we do however need to add it onto the back end so if we take slug i'm going to give in the slope as well into the create profile and into the edit profile okay cool so let's sign in so let's get this going so just a note on this look it needs to be unique and a best practice what you will see on most websites is we would actually want to do a client-side data fetch when this field is um on the change of this field query the database and figure out if this is unique and if it's not we can show an error message and actually not submit the form you're definitely going to want to validate this so you can only have um things in the form of a slug so you can do hyphens underscores um and to be honest that's something that we're not going to cover today but yeah you wouldn't ship this to production like this um hi my name is adam and then facebook instagram says create that let's edit that profile it didn't pull in the slug that's because we're not actually selecting the slug in our query so slug is going to be true as well so let's refresh and then obviously when we refresh just because this is in local state this is editing on the index page when we refresh of course we're not going to be editing anymore um but that is working come say hi so we've edited that that's all good and everything is working it might be good to on our editing page here if we pass set editing equals set editing so i'm gonna pass the set editing update the state thing i've lost my words um and then on edit profile what i'm going to do not this on edit profile i'm just going to add another button so let's pull in set editing like this i'm gonna have another button just outside the form button cancel um we can do something like that and then the on click of this is going to be set edit in to false and it will update that stay again so if you're not familiar with pass in passing props around basically we have this function set editing and that lives on our index page and then we're displaying this component again this this component lives within our index page almost so what we can do is we can pass down this function to the child component set it in and of course the stairs managed through the index page but we can pass this component down to the edit profile component so then within the edit profile component we can use that function um and it will update the index page like that so if we cancel then you see we're not getting the refresh it's just canceling nothing is happening so that's a nice little i don't know quality of life thing that i would add on there as well cool so the other thing that we're not doing is in display profile we're not displaying the slug um so let's do that and of course what you'd actually want to do is probably do like some styling like that um i'm not trying to make this the best styled website to ever exist it's more about the logic as you can see but let's put those spaces and it just looks a bit cleaner um and of course we could probably run a bolt this section of it like you just do a span tag like that in there put your class name equals you know font bold and that's looking quite a bit cleaner just like and i just said i wasn't going to do this but let's do it that makes it look a lot cleaner okay so then we've got phone [Music] twitter facebook and instagram there we go that's looking a bit bad cool so now we have this look and like i say the slick field one way of doing it and the way i would probably do it is generate it from the name so it automatically generate the slug if it's not unique so there's two adam richardson's then you'd append like one two or something like that and just like some digits on the end of it there and then allow people to change it but you're going to do that data fetch you do that on the client side to see is that unique um then if it's not you would shoot back an error um but yeah that little bit of logic will take quite a few minutes to do and it's probably beyond the scope of this so let's um let's create the actual front end so inside our pages folder let's make a folder just called profile and then we want to create what's called a dynamic route and then to do that we're going to wrap it in brackets like this and then it's just going to be slog.tsx and we're going to export default function we'll call it profile page and then let's return the div with the hatch on and then let's put profile page so if we now navigate to localhost 3000 slash profile slash adam richardson we have got our profile page so that is amazing that is exactly what we want however we want to have some information on this page and we want to statically generate this page so to do static generation we use um a function called get static props and this also needs to return an object and then we're going to return props and then we're going to return profile and let's just return null at the moment so let's do our data fetch first so let's import prismaclient like so and we're back on import prismaclient so then we'll say const prisma equals new prisma client like so so then we will need to do a search and again it's just worth pointing out even though we're importing this on this file because we're only using it within get started props this is only executed on the server it's not bundled into the front end so let's do accounts profile equals find no equals await so let's make this async and then we're going to bring in the params and i'll show you what those are in a sec oh wait dot prisma.profile.com first where the slug is params dot slope and then we want to return that profile like so we're gonna take the profile and we're going to console.log the profile so now what we should see so we need a get static paths function so if we do export const get static paths this also needs to return an object and we're just going to say fallback is going to be true and the paths is an empty array pretty sure that's the right syntax okay so we've got our profile so that's good network error don't know what happened now let's try again interesting and now we have our profile so one thing where we're doing um dynamic routes and what the fallback is true we can bring in uh next router from next router and then inside of here we can say cons router equals use router and what we want to know is it's going to say if router dot is fallback then let's just return um a div that says loading so we're loading loading loading loading loading doing the data fetch and now we have our profile page okay so the logic is pretty pretty straightforward so get started paths let me explain this a little bit and i've explained this in the next js getting started course get stack paths basically when you're doing stack generation you would normally do it one of two ways you will either declare all of the paths up front so if you have a quite a small blog then you might inside this path you will perform some logic and do a data fetch for all of the slugs for your blog posts and then what is going to happen at build time is this function will be executed it will find all of those pages and it will build all those pages in advance now you can also have a fallback board so if you don't know if you've got a huge huge blog with thousands of thousands of posts clearly your build is going to take a long long time if you want to build all those pages in advance so if that's the case then you will do fallback dynamic routing where basically the first person to load this page it will go and do a data fetch and then while while that is happening on the back end the server it will build the stack page so everywhere every subsequent visitor will have a statically generated page so that's the route that we're going down with this because imagine if everyone if millions of people go make a business card which is totally not going to happen given that's not the point of this um but if it did then you get again we wouldn't want to generate all those directly on build so this is why we do this if the router is in fallback so we're saying if you go to that slug and it's not statically generated then it's going to try and do the dfetch and the router goes into a fallback mode so when that data fetch is happening so the router is in fallback mode it's going to be loading and then the router comes out of fallback mode once it has found the data if it doesn't find anything then it will fall off all and then essentially on the front end we are just going to want to display this so we've got our profile page here we're not going to want to display the slug but we are good to go and you will see what um what is happening obviously it's going into fallback every time because we're in depth mode but when you deploy this you'll get fallback mode the first time it's visited but then after that it's just going to be a static website so then of course you would want to you know format this and make it look really nice and then you would have a link for everyone to share so another thing that maybe you'd want to display is we have the little image from google images um you might want to put that on image from why has that come back nearly finished now let's leave it image from next image and then we can just display an image source is going to be session oh do we have hmm that's interesting yeah because we're not actually yeah we're not actually fetching that session but what we are doing we're finding the profile so we could say include um the user that's true include user true and then where would we do the select select so user select include user as true yes then we can bring the user back so then we're gonna have profile dot user dot image is that gonna work and then we need to have width and height on that as well width equals 100 height equals 100 so it's loading i felt a lot of static props for some reason ah foreign so let me see what is actually trying to return that because i'm not sure why that wouldn't work user so including the user which is fine and that's the profile object which also includes a user object profile.user.image is correct let's um just come on down for a second and see if that is the issue pro every serializing profile that user created at ah because yeah i see the problem now so let's select user i don't think this is the right syntax but it seems to be satisfying the image image is true that can't be right so we want like email true name true let me just quickly check at the docks prisma client select fields select specific fields include relations profile definitely select name to posts select title to so we can just use a select and not the include so if we do email true name true by or true slugtrue facebook true twitter true instagram through anything else phone true user select image true there we go so you wouldn't use the include under select it's kind of the problem though okay so that's good so we got are we commented out the image bow and yeah if we're using google as a source for images like we are then we need to add this hostname to our next config so we don't have a next config so let's create a next.config.js i'll do module.export and then we can say images and then domains i think that is the right syntax not sure if it's image or images we'll soon find out see if it works yeah it says images here right i'm guessing it's correct there we go we now have that amazing image from google as well on that profile and yeah i'm guessing there's going to be quite a few of these different numbers um i've had that before with i think it was cloud narrower there was like 99 different numbers but i just created um just essentially mapped over like 100 things and then created it with the different numbers to add it in there so yeah you might obviously need different numbers so that is pretty good we are sorted i think i would say again to productionize this what you would actually want to do is add um add some open graph tags to it um so the title of the page was correct and of course you would put in to put in an actual title um you know add next head as well so then import ahead from next head i'm gonna add a heading here with the title and then we can put in profile dot name so at least we have a title profile.name dash contact information there we go so yeah hopefully this was a good introduction to authentication sending data to and from a database using prisma um like i said quite quite a distance from a productionized app um i would say the two main things for me would be your open graph stuff so that when it's when these details are shared it's shown image names and things correctly um because that's kind of the whole point of the app so you could share this page and then definitely that validation on a slug you would not want to deploy with you know just a slug field that you can submit everything to and validation on everything is hugely important like there's so many like having just text fields that are totally up to the user you're you know you generally want to minimize those on a website um and if you do need to have them then you would massively authenticate them like in the name field for example you know you would you would authenticate the name a slug you know there's regex which will define us look um but certainly in the name you don't want to allow numbers or special characters or anything like that fun you know you just want a certain form of numbers twitter you know you just want the the url would have to start with you know https twitter.com followed by a certain number of characters same with facebook and insta you would probably validate all of these fields and you can do that both on the front end so for 99 of people using your website that validation would be on your form um but then also do validation on your back end because you know there may be some clever people that want to just send requests to your back end without using your front end so you're still going to want to validate that input on the back end as well so yeah i would definitely do that to get this productionized but hopefully this was a good introduction and you've learned quite a few things by going through this so it doesn't look amazing we're going to be doing more tailwind css videos um and clone videos in the future for styling and things but um yeah it's it's quite a long video already so i'm gonna call it a day with this and i will see you in the next one thank you
Info
Channel: Adam Richardson
Views: 339
Rating: 5 out of 5
Keywords: nextjs, react, tailwindcss, nextauth, authentication
Id: Fn6YhLrR-vk
Channel Id: undefined
Length: 98min 57sec (5937 seconds)
Published: Sun Sep 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.