Learn NextJS 13: Build a Modern Full-Stack E-commerce App with TailwindCSS + Stripe + Zustand

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's good team welcome to another small James coding tutorial where today we're going to be building an e-commerce store a full stack eCommerce store using next.js 13 tail 1 CSS zest stand for State Management and stripe for billing and transactions it's an absolutely massive tutorial as nexjs have released a whole lot of changes with their latest version they're all absolutely phenomenal so I definitely recommend jumping on the bandwagon and we'll be putting them all to good use inside of this e-commerce store you can see it's a fully responsive page looks great we have a little cart model we can click on a product we get routed to a secondary page we can add the item to the cart we can add it multiple times come back to the home page navigate to The Orchard of apples we can add that to our cart three items in our cart everything looks brilliant and then at the end we have a fully functioning checkout so we can click on the checkout button just here that takes us to a stripe checkout page with all of our products and we can test this out fill out some demo information right here pay and it's going to successfully purchase all of these premium fruits take us to a successful checkout page and we can route back home and do the whole thing all over again you'll be able to view all of these transactions inside of your stripe page so that all works too and at the end of it you'll be an absolute master of all of the latest and greatest features of next 13. anyway that's it time to get into the code if you enjoy the video don't forget to like and sub helps me make heaps of these tutorials and without further Ado let's sell some fruit so to get started we're going to begin inside of our terminal and we're going to be in the project directory of our choosing and we're going to type MPX create next app at latest and we're going to give our project a name so that is going to be next js13 store if we hit enter we're going to get some configuration to do inside of our terminal so we're not going to be using typescript for this we will go with eslint we will not be using the source directory we will use the experimental app directory this is part of next 13's new features we'll keep the Elias the same and now we're going to have our project configured for us and now that that is all finished we can CD into that project directory so CDN to nexjs13 store and we can go ahead and open this up inside of our Visual Studio code editor so now that we have that open let's just take a second to look at what we're actually working with a lot of this looks standard to next JS however there are a couple of things that have changed in next 13 one is this app directory that we selected to use this is instead of having like the pages the components The Source directory all this kind of stuff it's now all done inside of this app directory inside of our app we have a couple of files the most notable ones are the page.js the layout JavaScript and the global CSS we'll kind of dive into this more later but the page and the layout are reserved keyword reserved file names that do specific things inside of this app folder and obviously since the Page's directory is gone now the routing is going to be done directly from our app component and where typically we would render the index.javascript file for any folder directory level within this folder now it's going to be looking for the page.js so in this root level directory the file that's going to get rendered is this page to JS all this content right here and the layout.javascript is the second Reserve file there's a couple others that we'll be making later and this is just going to wrap our app wrap our page.javascript file and any sub pages that we Define and so this is where we'll soon make our header and footer and stuff like that but what we're going to do in here is open up a terminal inside of our Visual Studio code editor and we're going to come over to this next JS documentation page just here to initialize Tailwind with our project the link to this page will be in the description down below so be sure to check that out if you're looking for it and we're just going to copy and paste these commands directly into our project super simple so we'll copy that one paste it in and run it onto the next one so now we're going to have to copy this content and update the tailwind.config.javascript replace this content tag and since we're not using the source directory we can get rid of these lines just here the next thing we're going to do is come into our Global CSS and replace everything in here so we can get rid of all of that and replace it with these three lines of code and finally we're good to boot up our project so we'll type MP and run Dev and that's going to a startup on localhost 3000 in my case it's going to be a localhost 3001 because I already have something running on localhost 3000. so here we have our boilerplate code that I mentioned is inside this page file we're just going to hit go ahead and get all of it we don't need any of this information nice and empty and what we're also going to do is get rid of the Styles input just here we're going to remove the class name on this file and we're just going to go ahead and delete this modular CSS file because we're not going to need any of those in our project and now in here we can test if our Tailwind is working by typing background green 200 and giving the page A Min height of the screen and we can see that our document does indeed change and so that is working perfectly so just like that we have Tower 1 CSS working inside of our next 13 project the next thing we can do is apply some font families to our entire project and as I mentioned the app is kind of the main entry point for all of our componentry and this file is wrapped by this layout.javascript file so here the children is going to be everything that is inside of these main tags and so what we're going to do is start off by styling the body of the document instead of giving this background green and Min height of screen we're actually going to give the body a minimum height of the screen a display of flex and a flex direction of column and the first thing we're going to do in here is apply a Google font family so next js13 has added an excellent feature that means we no longer have to worry about the import link tags to get Google fonts available inside of our project instead what we can do is wrap this class name inside of the curly parentheses and just like we have in here we have this enter and this import this font import from Google fonts we're going to go ahead and paste this inside of our file just here instead and now what we can do is we can Target enter and we can access its class name and we can append that to the end of our typical class name our Tailwind CSS Styles ensuring that you leave a space between the last style and the inter-class name so now if we refresh the page all of our text in here should experience that font family and we can see that it does indeed so that is nice and neat we also note here that we have some metadata so while we're in here we may as well just update this this can be the name of our store which is going to be a fruit shop just like that if we take a look that has updated up the top just there and the description could be whatever you wanted it to so we might say hyperinflated fruit store best prices 2033 so now the next thing we're going to do is start adding some header and footer components to our page and to do that we are going to add some more styles to this body tag the first one is going to be a relative Style just like that then in here we're going to define a header tag beneath the children we're going to define a footer tag and we're just going to wrap the children inside of a div and we're going to give this div a class name of flex 1 and that's just going to push this photo content to the bottom of the page so if we're occupying the full height of the page we can see that this content exists down here right there you can just see it so that's at the foot of the page there it's nice and neat for the minute what we're going to do is just write footer in there and we can put header up the top so there we have the header and we're going to start off by styling the header and give this a class name of sticky we're going to set top to zero we're going to give it a padding of six a background of white a border bottom border solid border blue 900 so that should show up just down there which looks good we're also going to give it a shadow of medium so that it has a little bit of a shadow on the rest of the content we're going to give it a z index of 50 and then we'll add some text sizes so the default text size is going to be 2XL on a small break point we're going to increase it to text 3XL and then on medium text 4XL and finally on a small we're going to increase the padding to Aid so as we get bigger that will increase so we get that large header up there so that is all good we're also going to take this opportunity to add a head tag up the top of our document right here and we're going to use this to import a font awesome CDN package so that we can use Font awesome icons in our project so once again the link for this will be in the description down below and we're going to copy this link tag and paste it in the head of our document and we're just going to have to update the cross origin and referrer policy to have the P capitalized and the O capitalized and that's going to allow us to come over to font awesome icons look up the cart icon and select the shopping cart just here we can copy this icon and paste it inside of our header component so if we just open that up we'll have a header that just says fruit shop and H1 tag and then after that we can paste this icon updating class to say class name so if we come back to our document we can see that here we have fruit shop and now we have our font awesome icon displaying we're going to add a flex and style to the header we're also going to add item Center and justify between so that's going to push the card to the other end of the page for the H1 we're going to give it a class name of uppercase so that it's fully capitalized we're also going to give it a cursor of pointer and a hover so scale 110. so that way when we hover over it goes to cursor and gets a little bigger and while we're at it we're going to come into our Global CSS file use the asterisk selector to select every element in our page and just give them transition duration of 200 milliseconds so now when I hover over this it just is a bit slower so that's looking pretty good the other thing we're going to do with this H1 element in our header is actually wrap it inside of a next link tag just like that so you have to make sure that that gets imported up the top of your document just here and we're going to wrap this H1 tag in the link tag and provide an href to it and that is just going to bring the user back home so whenever they click fruit shop it's going to Route them back to this home page as for the icon we're going to give this some styling we're going to give it a cursor of pointer we're going to give it a hover state of text slate 500 so on Hover it's going to change color and we can see that in play just there when I hover over the icon so that Hub estate looks real nice and then if we come back into our main page the file that gets rendered inside of our layout at the root level directory the root level route just here so the slash directory we're going to remove this content give this main a padding of four just like that and we will come and add some content to that in just a second so at this point we're about ready to start adding some products to our fruit shop and to do that we're going to come over to stripe.com we're going to go over to their dashboard you may need to log in or create an account we're going to come up here add a new account it's going to be called fruit store we'll create that account and once that's created that's going to bring us over to a home dashboard just here where the notable features that we're going to be looking at one is this developer section just here and the second one is this live content so here it says test mode we're currently in test mode and you will need to make sure that test mode is enabled for you only when you deploy your project you'll want to enable live mode so live will actually start billing and processing your transactions so for testing and development this should be in test mode obviously you'll need to access your account to access the live data but that's pretty straightforward and the first thing we're going to do is come into our project directory and create a EnV file we'll also want to make sure that inside of our git ignore we have the EnV local there so that our EnV does not get pushed to any public repositories and in here we're going to create a stripe secret key is equal to and we can find that inside of our account by coming to the developers tab over to API keys and here we have two keys the one we're going to be needing to copy in is the secret key so you'll want to click reveal secret key and copy the entirety of that key over and paste it just in here like that save that file and then close that file so I just did exactly that saved my secret key inside of the EnV file and that's going to mean we are ready to install stripe so we can go ahead and install the API by typing npm I stripe that will add that to our package.json file we can see it right here and we can actually go ahead and experience the first really cool feature in next 13 and that is getting the static information so historically for something like this we would have used get static props we no longer have to do that we don't have to use any user fix or use state to handle loading data in server side we can actually just Define an asynchronous function that is called get stripe products just like this and we can turn our home page into an asynchronous function as well and we can say const products is equal to and call that function this will be pulled in asynchronously server side before this page actually gets rendered by default all pages are server rendered in next 13 means that they are extremely quick the data is loaded instantaneously we avoid having any client-side rendering so it's unbelievably easier to load data into your pages and all we have to do in here is say const stripe is equal to new stripe this will need to be imported at the top of the document and we can then pass in process.env.stripe secret just like that we're going to provide a backup of an empty string then a comma and a secondary argument and this is just going to be the API version which is going to be 20 20 0 8 27 that's going to initialize stripe inside of this function server side and then what we can do is we can say const res is equal to a weight stripe dot prices dot list and inside of this list method we're going to pass an object and that's going to have one key expand with the value as an array that is just data dot product just like that after that we can access all of our products so that's going to be res dot data and we can just return the prices and this will be accessible as products in our actual components unbelievably easy that's all it takes to fetch data from the stripe API with this new next 13th syntax absolutely phenomenal stuff so with that done we're actually going to have to add some products to our store we're going to come into this products tab just here click add a product and the first one is going to be a bunch of bananas I've already pre-loaded the images if you want to use the same images they'll be linked in the description down below we're going to save all of these to our local device and that means that inside of here we can just upload the images directly so a bunch of bananas is going to be right here I've already saved them all to my device we're going to give this a description it's going to say a bunch of beautifully ripe and healthy bananas we're going to come down there's additional options here we don't really need any of that information for this we're going to make sure that the price information is one time the bananas are going to be 37 because of inflation at the moment everything is very expensive and we want to remain competitive we're going to save that product that is our first product and then we can come back to the products add a second one so we'll add a product this one is going to be an orchard of apples we'll upload the Apple's images just here fresh fresh and more fresh and crispy apples exclamation mark these should all be a lower case just like that these ones are going to be 150 and we're going to once again make that a one-time purchase we can now save that product and then we can add the final one which is going to be the premium pineapple just like that we can get that image the pineapple this one is going to be it's basically like drinking fruit juice but healthier exclamation mark we're going to come down once again one-time pricing this one's going to be a flat thousand dollars save the premium pineapple and now we have our three products we can see them all Here and Now what we can do is they will be accessed by this code just here and we could go ahead and console.log products right here just like that and now we can boot up our project and since this page is still server rendered we would expect to see this consoled on our server side not actually in the browser or the client so we can go ahead and run that come over to our page just here the fruit shop reload that that did not work and that's because it's gone to a local host 3000 I closed my other application and we can see that that returned a promise and that's because we have to make sure that we await that so let's reload this page and now we actually get the products just here and that is all showing up so that's absolutely brilliant we can see we have fresh fresh and more fresh crispy apples and now what we can do is actually create two more components and once again these have reserved name so you cannot just randomly name components like this unless they have this particular purpose the first one is going to be loading.js and this is still in the root level app directory and in here we're going to export default function loading just like that and this is going to be a component a special component that will once again wrap our app similar to the layout except it acts in the same way as the new suspense tags and react work so basically they check for any promises in the children content and if they do then this page gets displayed so if I refresh this page we can see that while we're loading that data this page by default automatically gets rendered right there I could change this to have a whole lot of stuff and it just is absolutely amazing our loading behavior is all handled and we don't have to fuss with having a loading State inside of our app it's just all absolutely seamless so absolutely brilliant the other thing we're going to do is you know when we fetch data we would typically handle an error State and we can do that as well this is also a reserved component name so error.javascript this one is a client-side component but it's going to be very similar export default function error and in here we're just going to return div that says error dot dot dot dot bummer and so because this component is instead of being rendered server-side like our loading component and our layout and Pages this one is server side to make its server side we just add a little syntax at the top that says use client just like that we're going to wrap it inside of the quotation marks double quotations we can see that's exactly what the error message says just here to do and we can save that and if we have any errors pulling our data then we will instead just display this error component so once again next 13 absolutely nailed it on the loading fetching API data and error States and all that good stuff so now that we have our products available inside of our actual component we can go ahead and start styling it and so this is going to have a style of grid grid calls one on a small screen breakpoint as we go larger we're going to go to a grid calls two so that's going to be a double grid column and then on the third one we're going to go on a medium break point we're going to go to grid calls three and I should say calls two and here we're going to have our first component so we can go ahead and Define a component right here this is not going to have a reserved name so it's just going to be a typical component this one is going to be productcard.js and here we can use the RFC component trick to get that component up and running this is going to receive some props and we can import that in here by just accessing the product card that gets imported at the top and we can see that in this console of what products is it's an array and so that means we can map out our product cards just here we can use the curly parentheses to map over the products array so we'll say dot map we'll get the product and the product index we'll open that up and then we'll return a actually the product card we'll make sure we give that the key equal to the product index super simple and then we'll just pass the product down as it is product is equal to product we can save that once again reload this page we can see that our product card gets rendered three times on our page so that looks awesome that should also be grid calls not grid coal and the other thing I'm actually going to do while I'm in here is just wrap this main inside of a div and give this the grid classes just there paste that in there and instead in this top level component I'm going to give this flex and flex coal and the reason I'm going to do that is so that I can define a Max width on this element so that's going to be 1000 pixels we can set the width to full and the MX of Auto and that just means that when we come onto our large page our products will self-center and they won't just continue to get ridiculously large so inside of our product card now what we can do is destructure the product from the props and we should be able to do some styles to the product card from here we're going to want a second level of destructuring this one is going to have some more information so we're going to destructure stuff out of the product so if we come and have a look at the stuff down here the information we're going to need is the ID so this is going to be ID we're going to rename it give it a new Elias so that's going to be a price underscore ID we're also going to destruction out the unit amount which is just down here this is the actual price that we specified in strike for the product we're just going to label that cost and finally we're going to get the product itself so that's this whole object just here and we're going to call this product info so now that we have access to this information within our card we can go ahead and start styling the card and we're going to start off by giving a flex and a flex coal display of flex and flex Direction column easy breezy we're also going to give it a shadow a background of white and a hover state that gives it a shadow of large and finally a cursor pointer as for the content in the page we're going to be using the image tag where the source is equal to product info dot images and it's the first image in that index we're going to give it an ALT equal to the name which is something that we're going to we're going to have a third layer of destructuring so we're going to destructure the name and description out from product info so now we can put the name just in there easy breezy we can close that image tag we're going to give it a class name equal to with full height full and object cover so that's pretty straightforward we can see that these images load into our page perfectly so that's excellent we can access these images we're also going to want to make sure that we have a gap between the cards so we can do that just in here we'll give this a gap of four that's going to spread the cards out a little bit and now underneath the cards we can have a div with a class of flex and flex column and a gap of Two and a padding of four and in here we're going to have a div that has a class of flex items Center justify it between that's going to have an H3 tag that has the name so we should see that pop up just below a bunch of bananas and at the other end what we're going to do is have a paragraph that has the cost divided by a hundred because the cost is specified in cents and we can just put the dollar sign key in front of that underneath both of these we're going to have a paragraph that is the description easy breezy so now we have the description and I'm just going to make the description have a class name of text small so that the text is just a little bit smaller than everything else and now if we inspect this we can see that you know it looks good on all screen sizes we have our different products and we'll just want to add a cursor pointer that just needs to be fixed to pointer up there so now we have these images that looks excellent our three little product cards the next thing we're going to do is Define an on click Handler and that's going to Route us to a new page now in this particular instance we're not going to be using the link tag for our routing and that's because we're going to have some other functionalities in an on-click handle that we want to Define however the link is brilliant for main links because it's great for search engine optimization so if you've got different pages and stuff but for a product specifically it's not as important so in here we're going to define a function that's going to be on click Handler or we could even be on product click be a bit more specific and in here what we're going to do is say router dot push and we're going to push to a new route for this we're going to have to import router now it used to be from next router but the import has updated so now it's actually from next slash navigation so we'll Define our router up here const router is equal to use router just like that and then we can have the router component save that now here we're getting an error if we look in the console it will tell us exactly what the error is I'll refresh that page and it's saying that use router only works in client components and so because this component can be a client component we can just add that use client at the top and now we refresh that page Happy Days everything is perfect once again so we can push to a new route and that means that we're also going to have to create the route so we can do that in here by creating a new folder this one's going to be called Product an end product we can create a new file page.js and it's just going to be that main page export and here we can say export default function product page just like that this is going to be the function that gets exported and in here we can just return some jsx that we can return a div that just says hello for the second and what we're going to do is we're going to push to a product slash and then we're going to actually change that secondary slash to a query and it's just going to be price ID just so we can see how this stuff works and then we're actually just going to add the Press ID right there we can assign this on click to this top level card on click is equal to on product click and so with that done we can save this page this on click has been assigned to the on product click come back in here and if we click on a product we can see that the router does reroute us it pushes the new route it's the product route and we get the price ID as a query parameter and if we click on one of these images just here we now get the price ID as a query and we can go ahead and access that inside of this product component or this page by receiving the props just here and inside of here we can de-structure search params from the props just like that let's make sure we spell that correctly params and we should once again be able to console.log the parameters so if I save that page and we look down here we can see that we do in fact get the price ID so that is super neat we can go ahead and destructure out the price ID is equal to props so that's just one way you can do it uh if you wanted to have Dynamic routes here we've you know had the information saved in a query parameter if you wanted to have a path parameter you can have Dynamic paths by just circling any new folders inside of a curly parentheses and so this would just be your variable name that you would destructure in the exact same way so super straightforward to have Dynamic pathing here as I mentioned we just want the price ID the other thing we're going to do at this point is initialize a global state for our project and we're going to use zestan for that and we're going to essentially set a product that we select to our Global state and then read it in our second project and so for that we are going to create a new folder and this one is going to be store and we're going to do this inside of a curly parentheses because the curly parentheses means that the app folder will not recognize this as a route and it will not look for you know any parts or components or anything like that within it and in here we're going to make a new file called store.js we're going to quickly kill our server and type npm install the stand is absolutely amazing lightweight Global State manager you can even use it with like persist methods to persist to the local storage and in here what we're going to do is we're going to say import create from zestand inside of the curly parentheses and we're going to say const use cut is equal to create open that up and this is going to take a callback function that has a set and a get method open that up in a function and here we return the state so that's actually incorrect we're not going to open it up we're just going to return an object return us an object store and then here we can have all of our parameters so the first example might be the card we can Define it like that it's going to be a list of all of the products and the quantities we're also going to have a product that gets selected that's just going to be an object and then after that we Define a whole lot of methods that are going to be used to interact with our store so it might be add item to a cart and that's just going to be a function make sure we have a comma after each entry and here we're going to accept params and what we can do in here is destructure the new item is equal to params and then once we have access to this new item we call the set method the set receives the current state and we return a new state because the state is immutable so we can't mutate the state directly we set a new state that's like a version based off the original state so in here what we're just going to do we're going to return spread the Old State and we're just going to set cut equal to a new array so we'll say const new cart is equal to and we'll do that inside this function spread state DOT cart and then add on the new item so we create a new array and then we set card equal to that new array so that's super easy for the add item to cut we've got a couple of other ones we might also have remove item from cart it's going to be very similar we're going to take params open that up we will destructure out the item index for that that we're going to remove say is equal to params and then we'll once again call the set method take the state open that up and return a new state cut is equal to New Cut and here we can just do exactly as we have above and Define the new cart with a new card in this instance is just state DOT cut dot filter we use the filter method we'll take the element we'll take the element index and we just want to make sure that we return element index is not equal to item index so basically every other entry will return true this one entry that we're trying to remove will return first false and that will be removed from our cart the last one we'll do is empty a cart so that one's going to be especially simple we don't really need anything we can just copy all this logic once again and then here we can just not receive anything and just say new cut is equal to an empty array and set that so that is extremely straightforward as for the product we're going to add one up the top so we'll say set product and that is going to once again be this similar syntax we've been using we'll have the params and here we'll destructure out the new product is equal to params and now we'll just call this set method uh except this time we're going to be updating the product with the new product super easy so just like that we have our store configured we have to make sure we export default store sorry use cat just like that so now we can access it in other components and then we can come to our product card and we can set the state to the product that we have selected so what that's going to look like is first we have to access the function so we're going to say const set product is equal to use cart we import that into our component from our store it is a method that we can call we access the state and we return state DOT the name of the function so in here this was just set product so this is going to give us access to the set products uh term or this this function and now we can actually call it set products and we can pass in the product just here so we're going to define it const your product is equal to and this is going to be an object and in here we're just going to set this object and so that is going to be name description uh price ID cost and I think we'll also need the product info so that's pretty straightforward that's got all that information that we're going to need and now we can just set the product to the new product just here and that will set this product to our state and then reroute us to a new page so if we save that and come to our home route and obviously restart our application refresh the page we reload the Home Route and we click on the component we get re-navigated except now we should have set that state and now inside of our product we can go ahead and access that set product so we can say const product is equal to use cart import that from our store access the state and we can just return state DOT product and assuming our set method worked correctly this add I add a set product assuming this worked correctly then we should have access to that product in here because that's what this will become so let's just try and see if we can console.log product let's see if that works for us we got an issue and that's because this is a server render component whereas this actually has to be a client rendered component we don't need this to be loaded from the server so we're just going to add the use client to the page just there let's do that once more we click on Orchard of apples and we can see that we don't get anything back but if we look inside of our console we actually consult out the object so that is awesome and there it is all right there we have the cost we have the name the description and the product info where we can get everything else so that has worked you know better above and beyond perfectly we now have a global state that we can manage from or access from any of our Pages set and update that so that's phenomenal we're also actually just going to add one more entry just here and this is going to be open modal and that's just going to be set to false and we're going to set a method for it so set open modal and that is going to be set State and we're just going to return spread the state and the open modal value will just be whatever is the inverse of what it currently is so this should just have the open close or the inverse the Boolean value of the open model and this will be for when we have our checkout page so this is just going to be open modal it says pretty easy but anyway back to the story so if we come here we click on the pineapple page and we have access to all of that information so that is absolutely cash money and so the only downside with this implementation that we currently have is that if we refresh the page we see that we lose access to that store so in here what I'm going to do is just write an fcheck and it says if not product dot name so we don't have access to the name of the product and consequently the rest of the product then we're just going to say window.location.href is equal to home and that's just going to send the user back home so if I refresh this page it sends us home again we load the images we come back we have the information we refresh the page it sends us home so that is all good and working so now once we're on this information page we can just quickly go ahead and style it we're going to need a couple of things so the first thing we're going to do is actually just access all of the information and we're going to do that essentially how we've done it here so we can just destructure everything out of this product we already have access to the price ID so we're not going to double up on that one but we will make sure that we get the name the description and that should be pretty good for the minute and here what we're going to do is give this a class of flex Flex column and actually that's a lie we're going to go grid and grid calls two and actually that's also a lie we will go flex and flex column and inside here we're going to have a div and this is going to have a class of grid grid calls one and then on a small on a media Square on a medium screen we're going to bump up to grid calls 2. and we're also going to give this a width full a Max width of a thousand pixels so we put the variable amount inside of the square parentheses and then we're going to give it an MX of Auto so that itself centers itself so in here we can have a div this is going to wrap the image so we can have an image tag this is going to have a source exactly as it did in here so we could just go ahead and copy this directly so we can yeah as I mentioned we can just paste that straight in there so that should show our image let's see if that works that is not accessing it for us cannot read images let's just see if we can console.log product dot product info just here see what that gets us so I'm going to go back to the fruit shop let's come clear the console log we click in there we actually get an ish shoe and that's because that is undefined and that's because I'm a muppet we actually don't want this weird syntax just here we just want to destructure these values uh specifically we don't want to rename them with eliases so if we do that once more we load our page we click through we access the image that shows up that looks awesome now underneath this div just here we're actually for this step we're going to give this a padding of Two and a shadow so that it just sits around it and I'm actually going to make sure that that only happens on a medium screen so on those break points we'll have that underneath this div just here we're going to have a second div this is going to have a class of flex Flex call Gap 2 and we're just going to have all the information so we'll have an H3 that will just have the name under that we're going to have a paragraph that's just going to have the cost so it'll be cost divided by a hundred and then underneath that we're just going to have a class of text small for our description so that's kind of all of our information just there we'll want to make sure that this is padded in a bit so we'll say P4 we get a padding of four that's all good I might also just do one last thing this is going to have a div in here with a class of flex items Center justify between and wrap these two so that it sits across like this and then what I can do is increase the text size on these so I can say text extra large they're nice and big and then I can on a small screen say well actually first let's just see what it looks like on a big screen so if I come across we see that breaks into two sides we have that information over there what I just want is the price to come underneath the name so we're just going to say on a medium screen Flex column that's all centered and so now we just want to say medium items uh let's we'll get rid of that Medium items start so I'm going to put another side that it absolutely does and on a medium screen I'm also going to drop this size down so I'll say text Lodge so we should have honestly we could even just say text base so if we just look at that we have the price we'll actually just need a gap in here as well match the Gap from above the premium Apple a thousand premium pineapple a thousand dollars and then we have the thing down there and then the last thing we're going to do is have a button so this is going to be a button that just says add to a cart nice and simple we're going to give this a class of background slate 700 text white hover BG slate 500 and a cursor pointer and we're also going to give it a margin left of order so that it pushes itself to the right and we're also going to give it a padding X of 4 and a padding y of two so now we have a little add to cart button and what I'm just going to do is give this a paragraph a flex of one so that it just pushes the add to cart to the bottom down over there and so now if we come onto a smaller page everything looks nice and neat we can do that we can go home we can click on the orchard of apples we have the orchard of apples we have the description all the information looks like we might just want to add some padding to the top of this component so we can say padding four it's just going to push it down a little bit and once again if I come onto a small screen that looks great so that's super good the next thing we're going to do is just quickly style the footer so for the footer we can just come back into this layout file just here also the one thing we should note is that the layout has also wrapped these sub pages so that is just super convenient you can actually Define sub layouts inside of this second directory that will be applied preferentially but we're just going to use this one overall layout and in here we're going to give this footer a class of flex items Center Flex wrap justify Santa border top border solid and Border slate 300. uh we're also going to give it a padding y of just a padding in general of 10. uh so that should come up down the bottom there we have our little footer and inside the footer we're going to come to font awesome icons and we're just going to have an Instagram link so if we come over to Instagram just here we can copy this little component paste it inside of our footer make sure we change class to class name just like that we'll give it a text slate 700 a hover text slate 500 and a cursor pointer because people need to be able to click on it and we can just see that come up down the bottom it's pretty Sleek we'll obviously want to bump up a size so we'll say text 2XL that's just going to be a little bit larger so that looks right maybe on a small screen I'll say text 3 XL and on a medium screen we'll say text 4 XL and I might just drop the padding of this down to a 4. all right maybe a six now we'll do four and then on a medium screen we'll do padding eight so that's just like that looking pretty good the other thing we're going to do is just wrap this icon inside of the link tag so the capital capital L will have to make sure that's imported up the top and we're just going to give this an href equals to whatever your Instagram is someone's https slash slash www.instagram.com small James close that component and now when we click on that we would expect to be routed to the Instagram which we are so that's all good and we might also just add the target equals underscore blank so that that gets opened up in a new tab so that's going to open that up in a new tab instead of changing anything here so that's nice and so that's our footer all done the last thing we're going to do is actually make this add to cut functionality work properly so we're going to have to set this to a state and that is going to be inside of our product page just here so we're going to define a function or even better we're actually going to access the uh store that we defined so we set this add item to cart State just here we're going to come into the product and just how we access the product we're going to access that function pretty typical convention to just keep the names consistent to what you've saved them inside of the store so now we can access this add item to cart and we can create a function here that just says handle add to cart and in here we can say const let's see what it expects so this expects a new item so we will just say const new item is equal to open that up and we're going to give it a quantity and a price ID so in this case we're just going to do the quantity of 1 and the price ID is going to be equal to the price ID from above so that should be super simple and now we can just say add item to cart and passing that new item inside of an object and then our store method will destructure it and set it to our cart now that should be cool on adding the item to the cart we're going to have to make sure that the header updates and that we have a little uh badge displayed on our header and so what I'm going to do in here is actually create a new component in the root level and it's just going to be called header.js we're going to make a typical react component and at the top we're going to put use client just like that and in here we're going to move this header logic from here and paste it as The Returned value from this header we'll have to make sure that we do in fact import the link tag that's pretty easy and now we can just render out the header import that component right there so it's right there and we can have that all working and what that's going to allow us to do is come into the header component just here and we can now access the kite cart item so we're going to say cart items is equal to use cart import our store access the state and return the state DOT cart and what we can do is we can wrap our icon inside of a div uh we'll give the div a class of position relative Grid in place items Santa so that everything is perfectly centered within the page and then we can have a secondary div and we can conditionally render it so if cart items dot length is greater than zero and we render out this component so some conditional logic if this is true then Rend out the value in here and this is going to be a div with a class absolute top of zero right of zero close that div and in here what we can do is just have a paragraph tag that has cut items dot length so that should typically say zero I might just give this a background of blue 400 and a text white and a rounded full so that it's fully rounded let's save that we'll see if that appears up the top currently it's zero let's see if I just change this to true temporarily we can see that we get that zero appearing just there that obviously looks trash so we can fix that by saying class text extra small uh that puts it at the top maybe small is better okay small is pretty good and we're also going to want us to set an aspect Square on this and give it a height of maybe four uh that almost worked and in here we also want to give this a grid and place items Center so that the text is centered within that little Bobble and it looks like this might need to be a six so there we have the little badge we could possibly bring this text size up to base that looks fine too and now we just want to translate this absolute element so we're going to say minus Translate Y full minus translate X full so that should move it off to the side and this shouldn't be minus Transit should be a positive translate X so that we can see that that's where it's placing up here that's maybe a little bit far and I might just bring that down to five and small we might train try changing this to half instead of full and now we can see that we have that little cart item badge and we can go back to having cart items dot length there is greater than zero so now what we would expect to happen with all of those changes is for us to go into an item add it to our cart and our cart value to update let's see if I come back does that happen no that does not and so we're just going to console.log cart items and that is still an empty array cut items is still an empty array we add and we're not getting anything so our add button is currently not working and that's because we actually haven't assigned the function to the button so we're going to say on click and just have handle add cut in there so now when I click handle add cart we can see that it does in fact update that little badge and we can add loads of items to our cart so that's absolutely smashing that's what it looks like on a small screen so we might just come into our store our little badge and make it so that the text size is on a smaller or bigger screen will also give this on a smaller bigger screen and we'll set the default to four and the text size to extra small so now on a mobile screen it's just going to still look too big let's keep let's keep the height the same we'll just change the text size so that's better that's just going to say 26 and then on a big screen it also looks decent if anything we could probably bring the height up small height six and there's our little badge we also just want to make sure that this has pointer events none so that's just not going to do anything and we also want to give this whole cart this item here the cursor pointer and we want to move this um we want to change this to a group hover effect and this is going to have group in here and so this is also going to have group well actually that's probably fine so group just means it listens to the parent hover State and so if we hover over anything in this it will uh change that opacity so that is hunky dory now that we have the ability to add items to our cart we obviously need a modal to display them and so we're going to create a new component it's going to be modal.js and here we can go RFC to create the modal this is going to be a client-sized modal client-side model so we can say use client at the top and what we're going to have to do to make this model work is we're going to have to come into our layout file just here and when we have this body we're going to have to make a new div down the bottom and this is going to have an ID equal to a portal just like that and that's just going to be an empty div now what we can do inside let's just close a couple of these Pages we don't need that we don't need that don't need the page don't need the product card we need the little that's fine for the layout we'll need the header and we'll need the modal and in here what we're going to do is import react Dom react Dom just there from react and this is actually not the correct input it's going to be react Dom lowercase om and that's going to be from react Dom just like that and this is going to return reactdumb dot create portal and in here we provide the jsx that gets rendered and under this we access the document.getelementby ID and we target the portal and that says where to create the portal so essentially how that works is uh if I have some content in here let's see where is modal if we come into the elements of the page we look here's the body let's close the body we're actually at the bottom of the body we would expect to have a secondary div and we can see it way down there div ID of portal and that currently doesn't have any content in it and that's because we're not rendering out the modal but as soon as we render this modal component we would expect that to come up on the page and so I'm just going to render it in here under the top and I'm going to first say a const open modal is equal to use cart State and we're going to return the open mode we're going to return we're going to return a state.openmodal because I believe that's what we called it in our store this variable just here I might set it true by default for the second so we can access that and then we're going to say open modal if it's true and return the modal component that we have defined so we can import that and close that off so that should currently be true and we would expect modal to show up at the bottom of the screen so it does and so that means that this portal is working correctly but since we rendered it in relation to the body of our document what we can do is give it some cool styles so we can say it class absolute effects top of zero left of zero width is going to be the screen so we'll say 100 view width sorry with screen we'll say height of the screen just like that and we could say background slate 900 and we would expect that now to cover our entire page we can see that it covers almost all of the entire page we'll also give it a zed of 50 because it needs to sit above everything uh and so that is currently working and this should also be fixed so that it always sits on the page and now all we can see is the model and the model is working perfectly so that is cool this uh should not have a background of slate like that and here what we're going to do is have a first div and this is going to have a class of background transparent and an nset of zero so that it occupies the entire parent container so absolute an inset of zero and this is going to be used to close the modal and then after that we're going to have a div and this is actually going to have the contents of the model so we'll say class Flex Flex call Gap 4 and maybe a padding of four and here we can have a div that just says uh H1 cart just like that we can go ahead and grab an icon so we'll just grab the close icon we just want the X where's the X the x mark right here we'll copy that x mark into our document make sure we update the class name to eczema and so if we look at our cart we can see that popping up just over there we want to give this element a background of white we're also going to position it absolute and at the right of zero and the top zero we're going to give it a height of screen so that it occupies the full screen height and we're also going to give it a shadow so now we can really start to see the card over here and what I'm going to do is on a small screen give it a width of the screen and then on a anything larger than a small screen I'm just going to set the width to 96 but give it a Max width of screen just like that so that should actually do it here we have our cart as we come into a small screen it occupies the full screen width and then as we come out it just takes up what it needs so that's looking decent I might also just give it a shadow large just so it's very obvious that it's on top of everything and now we can give this div here a class of flex items Center justify between now we have the cut at the top and the little close I'm going to upgrade these two text extra large so they're a bit bigger I'm also going to give this a position of relative and in here I'm going to create another div with a class name equal to Absolute bottom zero left half minus Translate X half so this is going to center it horizontally we're going to give it a height of a custom amount so we use the square parentheses of one pixel a background of slate 300 and let's see if that shows up that doesn't so what are we missing background bottom we have to set a width and so the width is going to be two-thirds of the parent element so now we have this little line down the bottom there I'm also just going to boost the padding of this element just here and remove it from there so this is going to say padding four so that's you could even make that burger maybe padding of six now we have the little line down the bottom underneath the cart we're going to access the store Handler the open modal Handler in here so we're going to say const uh close modal is equal to use cart we'll access the state and we will return state DOT the value so set open modal what we're going to do is this will occupy you know invisibly let's just actually set this to background green 200. we can see that that occupies everywhere that's not the car and it sits underneath so we're going to listen to any events that click on this background window here and if they click out of the cart it's going to close the cart so we can set that back to background transparent just like that so now it's invisible but we can set on click as equal to and we're just going to call closed modal and that is going to just be that right there let's make sure that's spelled Modell not model and the other thing we're going to do is just come into our store and set the default value of this model to false so that it doesn't originally display and now our page is working and that is all well and good and we're also just going to come into the header well actually first let's just finish this so we've closed the modal on the click of the backdrop we're also going to close the modal on click of this icon so anything inside of here so we're going to say on click is equal to a closed modal so that will also close the modal if they uh click on the x button we might also just give that a cursor pointer and a hover opacity should be sweet and we also want to now come into our header and make sure that when they click on the cart or anything in this div that opens the modal so here we we already have access to the open modal so now we'll just add the on click here open modal that's a function that should open our model so now if we try that we click and we get an error and that's because that is actually the value of open modal that's not the function so that's my bad this should instead be set open modal so we could say handle open modal and just access the setup well honestly we could just call them the same thing so that's the function that would actually want to pass down not the actual State value so if I refresh that page let's do that again we load our store we click on the cart the cart opens up we click off the cart it closes we click on it click the X it also closes but if we click anywhere else it does not we can also access the cart from other pages so that is working well and it's totally responsive so that is amazing now what we want to do is add items to our cart and have them rendered out inside of the modal so here what we'll do is we'll say const cart items is equal to use cart State and we will return the state dot cart and now for all the items we want to basically just make it look all pretty and we can do that by coming under here and having a div and we're going to have a conditional display that says cart items dot length is equal to zero if it is we're going to render out one thing and if it's not then we'll render out something else if it is we're going to render out a paragraph that says there is nothing in your cart maybe a sad face and if it's not true then we're going to map over all of the elements and we will return this inside of react fragments so that react is happy and in here we can say cut items dot map cut item we'll also make sure we access the index so we can say item index open that up and in here we can return a div that has the key equal to the item index and for the minute we could uh just say cart item let's see what we uh you see the issue is currently what we're doing is when we're setting it we're only setting the price ID in the quantity whereas we actually need the name as well and honestly we could probably get there so let's just make sure that when we have the add to cart so that's in here add to cart Handler we'll also make sure that we set the name so that we can access the name so that is chill we should be able to Rend out the name just there we'll come back and style this in a second let's refresh the page start again we come to our home page we click on the orchard of apples we add the item to our cart we can now see it's available for us absolutely amazing if I refresh this page quickly we'll start from square one we come to the home page we click on a bunch of bananas and we come to our cart we have nothing in the cart we add the item totally responsive zest stand is amazing so that is beautiful now what we want to do is style these items so we're just going to make sure that this here has a class of padding of four a display of flex Flex column gap of four and what we're going to do is we're going to give each of these card items uh something a bit more special than this so it's basically just going to actually while I'm on it I'm just gonna while I'm at it I'm just going to make sure that we set the cost as well that way we can calculate a total cost which I think will be super useful but in here we can just have the H1 with the cartitem.name we can give this a class of flicks Flex call Gap two we can also wrap this inside of a div just here that has class Flex item Center justify between and that way what we can do is we can have the price up here so we can just have dollar sign cut item dot cost and make sure we have to divide that by a thousand as per usual so that should display all of that underneath both of these items so this div just here what we'll do is we'll access the quantity and so that will just say one so we'll have a paragraph that says quantity and that can just be uh I don't know one of them and honestly that should be just about it so let's and so here we have our little uh entry what I'm just going to do is come back into the code just here and give this a border left border solid border slate 700 so that should just show up on the side we'll probably want to just give this a padding of two so it's in so here we have the item we don't have the cost yes and we have the quantity and so I'm just going to give this a class of text slate 600 and text small so that it sits a little bit smaller than the remainder and coming back in here I'm just going to make this a px of 2 so that it's just like that so here we have our little item if I come back to the home screen and start again we can go into our product we can click add to cart that shows up we can see that we have the cost and you know we could come back home that's still going to be in our cart so that's nice we could now come into the pineapples we can add the pineapple to our cart and then we have the premium pineapple and the orchard of apples so that is hunky dory uh what we're going to do to add on to this modal is after all of this stuff here we're going to give this an overflow of scroll this whole container has a flex coal and occupies the entire height of the screen so we're going to give this a flex of one as well and underneath this div right here we're going to have a final div that just says check out so it's going to be class name equal to border border solid border slate 700 text extra large and in here we'll just say check out so if I come over to the modal that's down the bottom just there you can see that we're going to give it a padding of actually we'll give it a margin of four so that pushes it in a little bit we'll give a padding of eight so that it's nice and big maybe sixes enough and I'm going to make it font semi bold uh no I'm not going to do that it's going to stay the same font but we are going to make it uppercase and we're going to give it a grid and place items Center so that the text is in the center now we have a nice little checkout button and we're just going to say hover opacity 50 60 cursor Point him and now that's just going to be our little checkout button so obviously that's pretty much our whole application working which is super excellent really nice everything is super responsive if we come down onto a Mobile screen everything looks good we can access the cart we can close the cart everything works really well the last thing we're going to do now is actually configure the checkout which we are going to do using this API route just here hello and currently they have this one little route so nexjs obviously serves up a node.js backend and that's what we're going to be doing in here and so we are going to start off by uh inside of well actually we're just going to delete this to you know first things first delete that that's all gone and we are now going to make a new folder called API and inside of API we are going to create a file called checkout.js so this is going to be a back-end route and in here what we're going to do is export an asynchronous function get and we're going to access the request and what we're going to say is return new response so it's pretty similar to what we've had before hello so that's going to do for now except that's a complete lie we will do that in a second and above this the first thing we're going to do is start off by accessing the body of the post route so this is actually going to need to be a post route we're going to say const body is equal to Json dot pass request dot body so we're going to pass the body of the request and we're going to say f body dot line items which is a thing that we're going to create dot length is equal to zero then we're going to return a new response of hello and a status of 403 and I think we should actually be able to access the res just here response so we could actually use a typical method instead so we might actually just return res dot send status 405. let's see if that works if we do actually have items we're going to say a try and catch block uh in here we're going to make sure we catch any errors and we'll console DOT log broke we're going to try to initialize stripe so stripe is equal to new stripe import that up the top we're going to do what we have done before and just say process.env dot Secret key stripe secret actually that's what it is a double question mark and then the backup and we're going to do just like we did before and pass in the API version which is 20 2008 uh 27 technically there's nothing stopping you from doing a newer stripe version now what we're going to do is Define a session so the session is equal to a weight stripe dot checkout.sessions dot create in here we're going to provide a success URL which is going to be https or piece slash slash localhost 3000 success will also Define a cancel URL uh make sure we have a comment in between them so we'll have to create these routes in a second we're also going to provide the line items which is going to be a body dot line items and finally we're going to have the mode which is going to be payment and then we're just going to return res dot status 201 dot Json and we're going to send back the session just like that if it doesn't work then we're going to say res dot send status 500 and console.log the error I think so that should be pretty good for our backend route which is awesome now we're going to have to construct this from our modal so in here what I'm going to do is create an asynchronous function called checkout pretty easy and what we're going to do is construct the line items and that is going to be const line items is equal to products or actually I'm sorry cart items dot map will get the cart item open that up and in here what we're going to do is return an object that has the price ID so that is going to be cart item sorry that's just going to be price is equal to price cart item dot price ID and then we're just going to set the quantity to uh one so it's going to be the line items after that what we're going to do is we're going to say const res is equal to a weight Fetch and we're going to go to slash API slash checkout I'm going to open that up and pass in some options so open that up in curly parentheses we're going to set the method to post we're going to set the body to Json Dot stringify and in here we're just going to have the line items object and then after that we're going to say cos const data is equal to a weight res dot Json access that Json and then we're just going to use the use router so we'll import that we'll say const router is equal to use router make sure that gets imported from next navigation and now we can just say router.push the success URL uh so that's going to be data.session.url just like that so that should be just about everything that we need to check if that's working we'll just need to assign this to the checkout just here we'll say on click is equal to the function check out so let's give that a shot we have our three items we click checkout we get an arrow we can go look at what the problem is by checking the network tab here we can see we got a 404 which says not found and that didn't work so what I'm just going to do is change this to a Handler function just like that and we're also going to add in some code up the top that just checks the method so above this here we're just going to say uh if request dot method is not equal to a post then we're just going to return res dot status 405. and that's going to be send status 405. so let's just go ahead and re-run everything we will refresh our page entirely we'll come home refresh our everything will load in our products we will add a product to our cart we have an item in our cart let's just really expand this open wide so we can see the network request let's hit checkout once again we get 404 and the reason that's not working is because that actually needs to be renamed route so what we're going to do is create a new folder in here and this is going to be called checkout and inside of checkout we're going to create a new file called route.js copy all of this code into route.js paste that in there and then delete this file so it's the same thing except now we should also be able to come back and just Define that as post and comment this code out just there so that should now do the trick we've restarted that we get the 500 server error so that is progress and if we look on the back end we get a nice error log and it's a Json issue so we should be able to look at the payload we have the quantity one we didn't get any line items so that's a problem so for whatever reason the price didn't add so let's just make sure that when we add that to our thing handle item price ID and did I spell that correctly price ID that is correct we could even console.log cart item let's just take a look at what it is we will come over to our console let's hit checkout we get this information it doesn't have a price ID so the price ID is obviously undefined and so that is an issue inside of our model that we can also take a look at so let's just here we'll console.log cart items make sure that comes up properly we come in here we look at the card item and we can see that the price idea is still undefined so that's an issue with how it's being set and that is getting set from the page.javascript so handle and cut this is not working uh price ID price ID price ID let's try setting it like that and we'll also console.log price ID price ID let's see if that works and that is the issue we actually need to make sure that we destructure the price ID from the search params that is the issue that I was having there so if we come back home refresh this page back to square one we add that to our cart we now have access to the price ID and we should be able to check that out we still get an error let's just go and take a look at that we can have a look at the network request for this too so there we have access to the price IDs inside of line items and the quantities so that is perfect and it looks like it's not enjoying passing the body so let's just console.log request.body we might not even need to pass it potentially and let's just try that once more that's restarted let's check out and now if we take a look we can see that it's a readable stream and let's just make sure that when we send that out from our modal that we also just set the content type so we will say headers and we'll say content type is equal to application slash Json because it seems to be reading as the wrong type of information so we'll refresh that send that once more what error do we get and this is giving us problems because I'm a muppet what we actually want to do is await request.json so we can access it that way that's going to give us the body of the document then we have the line items and now we have a secondary problem which is that res dot send status is not a valid response and so we're going to go ahead and use their style of response which is just going to be this new response and we can just say error we can give back a 405 just like that and we can copy and paste that wherever we send back a status which is just here so let's give that a shot and as for this one what we're going to do is we're going to return next response just here so that will need to be imported up the top from next server and we are just going to pass in some Json and that is going to contain the session just like that so let's make sure that's restarted we'll give that one more shot and that totally works so now we can go James this actually isn't going to work for the second because we're quickly going to have to create a new file with a success route and that's going to need a page Dot JavaScript and in here we can say export default function success page we can just return a div that contains a link that just says back home we can give this an href equals the Slash and we can also just say nice and we can do the exact same with our cancel route so page.javascript export default function cancel page return uh link just same as before back home and we'll wrap that inside of a div that says gutted easy breezy so now that's all working if we go ahead and just say banana at test.com we can use all the test information uh that they give us hello noodle and we should be able to pay we get a successful checkout and now we get routed back to the home of the fruit store and that purchase has been successfully muted so we can click back home that takes us back home and honestly Bob's your uncle you have a full stack application just like that so once again just to show how it works we can click on the bananas add the bananas to the cart check out the bananas we get taken through to a checkout page specific to the bernardins we can say test2 at gmail.com use the test info uh all of it and it's just absolute magic totally works fully functional eCommerce store and well done that's pretty much it my friends you have absolutely nailed this tutorial we are at the end you have a fully functional e-commerce store we've used tail1 CSS all the latest and greatest of next js13 we have used their API endpoints their routes and stuff like that we've looked at how we can do State Management with the stand absolutely massive tutorial and I'm proud of you guys for getting him if you've enjoyed the video don't forget to like and sub super appreciate it and it helps me make more tutorials like this thank you so much for watching and I will catch you guys in the next one peace
Info
Channel: Smoljames
Views: 17,854
Rating: undefined out of 5
Keywords:
Id: oLPgc5Fp2Ts
Channel Id: undefined
Length: 87min 23sec (5243 seconds)
Published: Mon Mar 27 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.