You are a JSON assistant. You only reply in valid JSON and never in normal text. Give me a score for the difficulty of a video information provided below. I expect a single "result" property with a float from 0 to 1 in it.
Title: How To Build A $1,000,000 SaaS In 7 Hours
Language: en
Description: Try Clerk: https://go.clerk.com/J5ucSbS
Try Neon: https://fyi.neon.tech/wds2


Building a SaaS is the ultimate goal of many software developers, but it is not easy. In this video I will show you how to create a clone of the Parity Deals site (which earns well over $1,000,000 per year in revenue. I will also show you best practices for creating large scale SaaS applications so that you can expand these concepts to any SaaS.

📚 Materials/References:

GitHub Code: https://github.com/WebDevSimplified/parity-deals-clone
Try Clerk: https://go.clerk.com/J5ucSbS
Try Neon: https://fyi.neon.tech/wds2


🌎 Find Me Here:

My Blog: https://blog.webdevsimplified.com
My Courses: https://courses.webdevsimplified.com
Patreon: https://www.patreon.com/WebDevSimplified
Twitter: https://twitter.com/DevSimplified
Discord: https://discord.gg/7StTjnR
GitHub: https://github.com/WebDevSimplified
CodePen: https://codepen.io/WebDevSimplified


⏱️ Timestamps:

00:00:00 - Introduction
00:01:10 - Project Demo/Overview
00:04:35 - Next.js Setup
00:07:35 - ShadCN Setup
00:09:07 - Navbar Design
00:15:50 - Clerk Setup
00:18:29 - Landing Page Design
00:46:44 - Sign In/Sign Up Pages
00:50:16 - Dashboard Navbar Design
00:54:04 - Private Route Setup
00:56:44 - Database Setup
00:59:40 - Type Safe Environment Variables
01:03:40 - Drizzle Setup
01:19:17 - Clerk Webhooks
01:26:51 - IMPORTANT: Database Clean Code
01:29:28 - Finish Clerk Webhooks
01:33:00 - Dashboard Home Page
01:37:25 - New Products Form
02:04:30 - Product Grid
02:31:00 - IMPORTANT: Caching System
02:52:40 - Edit Product Details Form
03:08:34 - Edit Product Country Discounts Form
03:52:10 - Start Edit Product Customization Form
03:54:36 - IMPORTANT: User Permissions
03:58:10 - Finish Edit Product Customization Form
04:16:49 - More User Permissions
04:24:40 - User Subscription Page
04:36:10 - Stripe Integration
05:08:49 - Banner API
05:31:52 - Analytics Page
06:25:57 - Fixing Mistakes


#SaaS #WDS #NextJS
Caption: by the end of this video I&#39;m going to show you all the code you need to write to create a business that can easily earn over a million dollars a year and I&#39;m going to be doing it using the latest and greatest nextjs features and I&#39;m even going to show you how you can write your code in a way that is very modular modern and clean so you can extend this project to be as large and complex as you need it&#39;s honestly some of the best code that I&#39;ve ever written that I&#39;m going to show you in this video and to create this seven figure business we&#39;re going to be making a clone of the site parody deals this is a real application that as you can see I currently use I pay about $500 to $1,000 a year to this service and same with all of these other people they&#39;re all paying hundreds or even thousands of dollars to this service I&#39;m going to show you how to create a clone of it that does all of the same things and even improves on many of the problems that this site has and throughout this entire process I&#39;m going to be explaining exactly what I do step by step so you can understand why the code works why I&#39;m writing it the way I&#39;m writing it and what actually makes it clean code this is going to be a really long video but I guarantee if you stick through the entire thing you&#39;re going to learn invaluable skills that&#39;ll help you with this project and any other project you build [Music] welcome back to web dev simplified my name is Kyle and my job is to simplify the web for you so you can start building your dream project sooner and to understand how this project can earn over a million dollars a year we first need to understand what the project is that we&#39;re building I already talked about it being a clone of the parody deals website and essentially all this website does is figure out what country a user is coming from and then it shows them a different coupon based on where they&#39;re coming from so that someone from India for example can get a higher discount than someone from the US where maybe they don&#39;t even need a discount so for example I have here multiple different products and if I were to go into edit one of these products you can see if I click on the countries tab I can determine exactly what discount I want to give to different groups of countries and all these countries are grouped by the amount of discount that they should get so for example the purchasing poty in this group of countries is anywhere between 20 to 30% of the purchasing power in the US so someone from this group has about 20% of the buying power somewhere from the us so we can offer them a rather large discount while someone up here in this higher group we may not want to offer any discount at all because they already have really good purchasing power now since I&#39;m from the US I put a discount of 12% in here with a coupon Cod of test and if we go to the website where this is hosted you can see I get a banner at the top saying hey you&#39;re from the United States we support this purchasing imp parody here&#39;s a coupon of the code test to get 12% off anything on our site and the really nice thing is is we can actually customize exactly what this Banner looks like in this customization section we can change the text we can change the colors we can change the font size for example I can make it a really large font size give that a quick save now if I come over here refresh you can see it&#39;s much larger I can customize EX everything I want to do and I even have set up for CSS prefixes so you can manually customize the exact CSS that comes out so you can really configure it to be anything that you want it to be on top of that we have in-depth analytics on exactly what&#39;s happening for example we can see you know each day who&#39;s coming to our site we can see exactly what groups these people are coming from and even the individual countries everyone that&#39;s visiting our site is coming from and we can even determine it based on each individual product we can change the ranges and we can even change the time zone that we show this information in so for example if you want to see it in your your local time zone or UTC you can change that right there lastly we can manage all of the information about our subscription and that&#39;s because this is a full SAS application which is how it can earn over a million dollar a year because you can see on this highest plan you have to pay $100 a month and you only need a th000 people paying $100 a month actually less than a th000 people technically but a th000 people paying $100 a month is over a million dollars of year in income for your product and that&#39;s something that you can easily achieve with the product that I&#39;m about to show you how to build so you can see here we have a SAS with different permissions and different levels of things that they can have for example about how many products their different monthly usage and so on and you can even manage your description and all this is handled inside a stripe so you can go ahead update your pan update your payment information and so on literally everything you would ever want to change or you can just you know manually say I want to swap to the $100 a month version and here you go I can just click Swap and it&#39;s that easy we also have in-depth permission handling for example if I log into a separate account that is on the basic free subscription plan you can see they don&#39;t have access to analytics and they don&#39;t have access to Banner customization and they can only have one product so for example if I try to create a new product I get a warning saying hey permission denied if I try to access analytics again permission denied or if I try to edit my product and I want to customize it again permission denied these are not things that you can change I&#39;m going to show you how to build all of that in this video and the best part is I&#39;m going to show you how to do it using modern tools such as nextjs and I&#39;m going to show you how to build it in a way that is clean code and maintainable which means that we&#39;re going to be able to handle all these things like permissions in a way that it&#39;s super extendable to literally anything you want same thing with caching we&#39;re going to have a really robust caching system I&#39;m going to have different rules and clean code practices in place to make this the best code that you could possibly write so no matter how large this code base grows it&#39;s still going to be just as easy to work on as when you just getting started now to get started I just have a blank text edit to open we&#39;re going to be using nextjs for our framework of choice so npx create next app at latest to get the latest version and we&#39;re going to install that in the current version of our directory I&#39;m going to hit yes to proceed I&#39;m going to say I want to use typescript eslint Tailwind CSS The Source directory the app router and I don&#39;t really care about customizing my import Alias now that&#39;s going to go ahead and install and while that&#39;s happening I want to talk about our full Tech stack we have nextjs for our framework we&#39;re going to be using Shad CN and Tailwind UI for all of our CSS and styling we&#39;re going to use stripe for handling all of our different payment billing SAS Integrations and so on we&#39;re going to be using clerk for our authentication and we&#39;re going to be using neon for our database which is built on top of drizzle and postgress which is what we&#39;re going to be using for our omm and behind the- scenes database now Clerk and neon are sponsors of this video and it&#39;s really great that they&#39;re able to sponsor videos like this because they&#39;re tools that I already use anyway and it allows me to build these massive large projects in enely for free for you to be able to use because these take weeks of my time even months sometimes to build out so be able to share this with you for free is only possible with Clerk and neon sponsoring so I highly recommend checking them out if you like their product in the video now once we have our basic application up and running we can just npm run Dev and that&#39;s going to start our application we can open up on Local Host 3000 and we&#39;ll just see the boiler plate nextjs screen now before we go ahead and actually do anything the very first thing that I want to do is just take our code and clean it up a little bit cuz we don&#39;t need a lot of the default stuff for example I don&#39;t really care about having this vacon we can change it to our own inside of here I&#39;m going to pretty much get rid of all of these basic Styles except for the Tailwind ones I&#39;m just going to leave that in there and our layout we can keep these default fonts that they give us that&#39;s okay you can see we have our font showing up right here and then finally in our page I&#39;m just going to get rid of everything and Export a default function homepage and I&#39;m just going to return null from there just so we have a blank page to start with now the final thing I want to do is to set up our Tailwind config because inside this layout we have these different fonts that we want to be able to use so if we come into Tailwind we can get rid of this extension for the colors since we&#39;re not actually using those base colors anymore and instead we can extend the font families so I&#39;m going to copy in the code for this if we look over at our page our layout you can see here that we have a mono font being imported and a Sans font being imported so inside of here all that I&#39;m doing is I&#39;m saying okay for my Sans font I want to use that and for my mono font I want to use that and otherwise I&#39;m going to fall back to the default F font family so we can get that font family from Tailwind CSS and that&#39;s going to be coming from the default theme so we can just just type in like that and there we go now we&#39;ve extended our font family to use that font family directly from nextjs that we&#39;re importing the next thing I want to do is I want to slightly modify how my container looks so for my container I want to center it by default and this is just the container class that you add on to anything so anytime I add a container class I want to make sure that it&#39;s going to be centered I want to have some padding on the sides of 1.5 RM and I want to make it fill 100% of my screen size up to 1200 pixels at the maximum size it&#39;ll never be larger than 1200 pixels just so it doesn&#39;t get too wide so so those the only changes I&#39;m going to be making to my Tailwind config and that&#39;s just going to make it so my container looks a little bit better we can close out of that and we can close out of our layout now the next step I want to go through before we start building out some code is to install Shad CN so we can just go through the installation steps they&#39;re rather easy we can just run npx Shad CN at latus and knit and if you just put- D it uses the default values which is what we&#39;re going to do so I&#39;m just going to install that right now and what that&#39;s going to do is it&#39;s going to essentially set up a bunch of different files for us if we just wait a second for that to finish you&#39;ll see inside of our source folder we now have a lib folder that contains all of our utils and if I were to add something like this button component which I&#39;m just going to paste in here to add you&#39;ll now see that that&#39;s going to add a components folder and inside that component&#39;s folder is going to be our button right here which we can make any changes that we need to now the very first change that I want to make to our application is back inside of our layout I want to change some of the styles that we have here right now we have our fonts in this anti-alias thing but I also want to make sure that I set this to font sand to make sure it Imports the actual custom fonts and I want to set my background to my background color that way it has a slightly different background color on our page now I also want to modify some of the variables in our CSS file because that&#39;s really the beauty of using Shad CN is you can change any of these variables to exactly what you want in our case I want to change what our accent color is cuz by default the accent color is the same as this muted in secondary color I want this to be like a blue color that&#39;s going to be what our application is so we&#39;re going to use 193 as our Hue we&#39;re going to use 82% here as our saturation and then we&#39;re going to use 31% for our lightness and you could also add in a dark mode version of this but there is no dark mode in our site so I&#39;m just going to ignore that for now and move on to the foreground version and for our foreground version we&#39;re just going to set this to 0 0 and 100% which is essentially Pure White now before we bother with stripe Clerk or neon I want to go ahead and just work on creating the actual homepage this landing page of our application so the best way for us to do that is to separate our app into two distinct groups we&#39;re going to have our group for marketing this is like our homepage and so on and then we&#39;re going to have a group for our dashboard and I&#39;m actually going to put our dashboard group in its own URL so everything that&#39;s SL dashboard is going to be for our dashboard Pages like our creating products and all those different customizations that we talked about while anything in this marketing folder is specifically for things like our homepage and so on and the nice thing with doing it this way is it makes it really easy to see okay everything in dashboard is for our dashboard everything in marketing is for all of like our homepages and so on our landing pages and marketing and pricing tables all that jazz so in here let&#39;s go ahead and create a layout. TSX this is going to be a function which is our marketing layout let&#39;s get the children in side of there and we&#39;re going to say the children are a react node just like that now inside of this component it&#39;s going to be pretty straightforward I&#39;m just going to return a div that allows us to actually create some styling to wrap everything I&#39;m going to have a nav bar inside of here this is a custom component we&#39;re going to create outside of this component and then I&#39;m going to render out our children below that now the only thing that I want to do inside of my nav is you can see on this page when I highlight it gives me this nice color of like pink when I highlight so I want to add that pink color so let&#39;s add a class name here we can specify the selection class that&#39;s for tailwind and we can specify when we want to modify the background and we want to give it a specific color I&#39;m just going to copy over that color just like that so we can see that this color is going to be this purplish color but it&#39;s at a 20% opacity so now if I were to actually highlight something for example I put some text inside of there come back to my application and of course right now when I&#39;m refreshing nothing happens and that&#39;s cuz it&#39;s rendering this blank page here we don&#39;t actually need this page to be here I want it to be in my marketing layout so now it&#39;s going to render that blank page inside of here so let&#39;s make sure we give everything a quick save close out of that there we go and now if I give my page a refresh you notice we&#39;re getting errors that&#39;s because this should be a default export there we go so now when I highlight this pink text or this text you can see I get this nice pink background it looks relatively good now let&#39;s go ahead and focus on our nav bar because that&#39;s the next thing I want to work on and also to help keep my code clean I could put this component directly in my component&#39;s folder but this Navar is only for pages on my marketing layout so instead I&#39;m going to actually put that directly in this folder here called under score components by putting an underscore in front of a folder name it means it&#39;s ignored for all routing purposes so this will not do any routing and now inside of here I can create my navb bar. TSX file this is really great because now all my marketing only components can be in this folder right here this is just one small step on creating clean code which we&#39;re going to cover a lot in this video so now here I want to export that Navar component it&#39;s not going to take in anything and it&#39;s going to start by having a header because this is going to be the header of our application inside of there we&#39;re going to have a nav which is going to contain all of our different links and we can go ahead and create our links which come from nextjs now this very first link is just going to link to our homepage so we&#39;ll give it that right there and it&#39;s also going to push everything off to the right hand side you can see here we have our big link on the left and if I just expand my screen a little bit grab all of our other links obviously this is not super well mobile optimized but all those links you can see are pushed off to the right hand side again this parody deal site has a lot of improvements that could be made to it and we&#39;re going to be making those improvements so to push all of our other links to the right we&#39;ll say margin right of Auto and we also need to have a flex container to be inside of here to make that margin right work so we&#39;ll make this a flex container there we go we&#39;ll also put our items in the center while we&#39;re at it so we&#39;ll say items Center and a gap of 10 to separate essentially this parody deals from the text on the right otherwise if we don&#39;t do that we&#39;re going to run into a problem where we have all the text squished up together so we&#39;re going to fix that by putting in a gap there I&#39;m also going to give this the container class to make sure all of the content inside this nav does not get too large for example if we increase the screen size here and we zoom out you can see here it confines the size of the space that our nav can take up so that&#39;s essentially what our container is allowing us to do is just confine the space that everything takes up lastly just to make my font pop a little bit we&#39;re going to say our font is going to be semi bold so it&#39;s just a slightly more bold than normal font now inside of here I&#39;m actually going to put my brand logo and I&#39;m going to put that inside of its own component that&#39;s because I&#39;m going to use this in a lot of different places and I&#39;m going to use this both on my homepage as well as inside of my dashboard so this is a component that makes sense to put in this component&#39;s folder so we&#39;ll say here that we have our brand logo. TSX because this will be used everywhere inside of our application now I&#39;m just going to copy the code over for our brand logo and explain what it is cuz it&#39;s relatively straightforward all we have is a single span which we have a flex container set up on with a gap of two to give it a little bit of space we made the font semi bold which in this case is not super required but again we&#39;re just reinforcing that it&#39;s semi bold we&#39;re making sure it can&#39;t shrink down at all and then finally we&#39;re making sure everything is pushed off to the right hand side we could probably get rid of this that should still work just fine and we&#39;re also making this so our text is a little bit larger finally inside here we have this globe icon that&#39;s showing up and we have this span obviously you can create your own custom icon so on but this is just a really basic Bare Bones version we can get working so now let&#39;s import all this to actually see if what we&#39;ve written is working so inside here we&#39;re going to import that nav bar and if we go back to our application you can see at the very top here we have our logo showing up so far we don&#39;t have any other crazy styling going on but at least we have something working now to make it a little bit more obvious that essentially we have our nav bar at the top with different styles on it to distinguish it from the rest of our application let&#39;s style our header a little bit by giving this some class names so we can say here the class name on this is going to be Flex to be a flex container we&#39;re also going to put some padding in the y direction of six to space things out I&#39;m going to add a large Shadow on it so if we give that a quick save you can already see that now we have at least separated this a little bit I&#39;m also going to fix this to the top of the screen so we&#39;ll say fixed with a top of zero and we&#39;re going to make sure it fills the full width by using a w of full lastly to make sure it shows up on top we&#39;ll put a z index on it and the background color I&#39;m going to make it partially transparent so I&#39;m going to use my background color but I&#39;m going to make it 95% opaque so that means it has a slight transparency which which means if there&#39;s any text behind here it&#39;ll slightly show through which is exactly how the parody deal site works if I expand this and I scroll down you can see that you can see all the text behind it our site&#39;s going to have that exact same feature inside of our navigation as well now we&#39;re going to want to add the rest of our links down so let me just paste in a couple more links we have a features link a pricing link and an about link they&#39;re all exactly the same text of large and right now we&#39;re not going to create these pages so I just gave them blank HFS except for pricing it has an HF with an anchor on it that&#39;s because we&#39;re going to put the pricing on our page so this will scroll to that section so there is the rest of our links right there and again they do absolutely nothing when you click them now the final thing I want to add is going to be a link for signing in and signing out so we&#39;re going to have a span here to make that text large so we&#39;ll say text large just like that and then what I want to do is I want to come in here and I want this to either say dashboard or I want it to say log in so if we are signed in I want it to say one thing versus the other so this is where we&#39;re going to need to integrate clerk into our application which is a relatively easy process and it contains all the components that we need so the first thing we need to do is to install clerk so we want to say at clerk SL JS because we&#39;re using nextjs that&#39;s going to install all the different components that we need inside of our application and once we get that done we can actually see now inside of here we have a component for signed in and this is going to be only rendering out the content in here if the person is signed in so in here we can put a link that goes to our dashboard page if they are signed in just like this dashboard so now if the user is logged in it&#39;ll show dashboard we also have a component for signed out and this is only going to render if they are signed out and we can render the signin button so we can just say signin button like that and it&#39;s going to say the text log in now we are going to get some errors when I try to render this out because we don&#39;t have clerk set up on our application the first thing we need to do is to handle some Clerk middleware and we also need to wrap our entire application in a clerk provider so if we go to our layout we can come in here and wrap the entire thing inside of a clerk provider so this clerk provider just gives us access to the authenticated user and our entire application that&#39;s step number one the second step is implementing our middleware and then we need to hook up everything so let&#39;s go ahead and get started on creating an application just create an application inside a clerk determine how you want users to log in let&#39;s say that we want to be able to log in with GitHub Google and email that works fine let&#39;s give our application a name of easy PPP because that is kind of the name we gave our application we&#39;ll click create application and that&#39;s going to get us setup and now we can click on nextjs for installation steps and this will actually tell us how to install everything with nextjs we&#39;ve already gone ahead and installed this we can set up our environment variables next so I&#39;m going to copy that over come over to our application and I&#39;m going to create a EnV file just like that and paste in our file variables right here and the thing that I want to make sure that I do with this environment variable so I want to make sure I ignore this from our get ignore so we can come in here EnV and we&#39;re going to make sure that that is completely ignored from our application now the reason I&#39;m using EnV like this is because when I start to use drizzel it requires a EnV file so I can&#39;t use like env. loal so now we have those environment variable saved the next thing that we need to do is to create a middleware file and give it this exact code so I&#39;m going to copy this code I&#39;m I&#39;m going to create a brand new file called middleware dots I&#39;m going to paste in that clerk code right there by default this doesn&#39;t make any of our routes protected at all everything is still publicly accessible but we can at least do login and sign up and so on and I&#39;ll show you how to protect routes when we get to that point finally we need to wrap everything in cler provider like we did and that&#39;s literally it we&#39;re entirely done so now back to our application we should see hopefully if we refresh here everything will work and now you can see we have a login button because we are currently not logged in and when I click on this it&#39;s going to redirect me to the login page and so on so now that we&#39;re done setting up clerk before we bother with doing like signin sign out logic and so on I just want to go ahead and finish out our homepage cuz right now it&#39;s pretty Bare Bones so inside of our homepage we&#39;ll go to the actual page section and we should probably render out more than just null so I&#39;m going to come in here I&#39;m going to render out a fragment and I&#39;m going to break each of my different sections into a section tag so the very first section I want to cover is going to be this like homepage section so if we bring this out you can see here it has this kind of interesting radial background with some text as well as like a getting started button so I want to be able to incorporate all of that into our own page so the very first thing that I want to do is to work on that fancy background so we can come in here we can say the class name is going to have a Min height of screen it&#39;s just going to make sure this section fills 100% of the screen height and then we can specify our background now I&#39;m going to copy over the value for this background because it&#39;s just a very complicated radial gradient and I&#39;ll explain exactly what&#39;s going on so we have a radial gradient right here and essentially we&#39;re going between a few different colors we essentially have this first color which is going to be either that purple or that pinkish looking color and our second color which is the other version of that purplish pinkish color and then finally we&#39;re fading out to our background color at around 60% and that&#39;s just to make it so that this radial gradient only fills up this middle portion of our screen and doesn&#39;t extend to fill our entire screen now if I give that a quick save you can now see we have that purplish orish radial gradient in our screen that Fades out to 60 at 60% to our background if I were to remove this section with my background you&#39;ll see that this fills my entire screen not what I want that&#39;s why I have this background section on there so we have our really big complicated radial gradient set up next thing I want to do is just Center everything so we&#39;ll say Flex items in the center justify everything in the center and I&#39;m going to put my text in the center and I&#39;m also going to use text of balance which makes it so that when I shrink down my screen size my text stays as close to possible on the best looking lines instead of just having like one text on the bottom line like this one will it&#39;ll actually perfectly balance my text across multiple lines so it&#39;ll look even better than the homepage that we&#39;re trying to copy finally I want to make sure that I have a flex direction of column I want to have a gap of eight and I want to have some padding on the right and left of four so now what we can do is we can get our text inside of here I&#39;m going to have an H1 for my main text this price smarter sell bigger section I might as well just copy that text because we&#39;re going to use the exact same text then I&#39;m going to have a paragraph tag next and that&#39;s going to copy this exact text so we&#39;ll paste that into there and then finally I&#39;m going to have a button and this is going to be a sign up button so all I&#39;m going to do is when I click get started for free it&#39;s going to bring me to the sign up page so we&#39;re going to have our sign up button and inside that we&#39;re going to have our button from Shad CN now I&#39;m going to specify quite a few classes on here for example I want this to be a large button so I&#39;m going to have a large text size on here just like that I&#39;m going to have some pretty large padding on the sides and the top so I&#39;m just going to say p of six just like that I want it to be a rounded XL so it&#39;s slightly larger on the rounding a flexed as well as a gap of two and that&#39;s because inside of here I&#39;m going to have the text get started for free and then finally I&#39;m going to have an arrow that is going to the right so I want to get the arrow right icon and we can also specify a size of that which is going to be a size of five so now if I come back over to here you can see I have that button set up with all the different styling I want all I need to do is style my text to make it look a little better but first you&#39;ll notice when I shrink down my screen size you can see it&#39;s perfectly balancing my text across multiple different rows which is really something that&#39;s quite amazing I love that CSS feature so let&#39;s come in here and we can style out what our heading is going to look like we want our text to be rather large so we&#39;re going to say 6 XL but if we&#39;re on a large screen size I want it to be 7 XL and if we&#39;re on an even larger screen size I want it to be 8 XL so it&#39;s going to scale the font size with large my screen is I also want my font to be bold I&#39;m going to set the tracking to tight to make my letters a little closer together and then add some margin I&#39;ll show you what that tracking tip does if I remove this you&#39;ll notice how far apart my letters are spaced while when I add that back in it brings my letters closer together generally when you have larger font sizes it&#39;s better to use a tighter tracking because it makes your font a little bit easier to read instead of spreading everything out while with smaller font sizes it&#39;s better to have larger line spacing and have larger tracking to space out your letters a little more so again it&#39;s easier to read now for our paragraph here we can change our text I&#39;m going to make it a large text by default but on a large screen I&#39;ll make it a text of three XL to make it quite a bit bigger and I&#39;ll also maximize the size that this can bring to my extra large screen so that way it doesn&#39;t get too large so now if I just come in here and I make this a little bit bigger you&#39;ll notice that my font stays super big and it never actually becomes too wide because I&#39;m making sure I&#39;m clamping the size that it can actually be so it looks really really good on multiple different screen sizes so that&#39;s essentially the top section of our entire thing done we can close that down and move on to the second section which is a section that&#39;s like hey here&#39;s all the different companies that use this particular product this is a really great thing to have on a sales page to be like hey look at the proof I&#39;m this good and all these other companies use me so we can come back over to our application here I want to have this section b a class name with a background of primary and I want to have my text be primary foreground so essentially it&#39;s going to invert my colors we&#39;re going to have this nice blackish background with white text on top of it then inside of here I&#39;m going to have an H2 that&#39;s because we already used H1 up here so I want to have a heading for my second section being H2 and this is going to be the text right here I&#39;m just going to copy the text over same exact thing that&#39;s on their page trusted by the top modern companies and we can add some styles to this for example we can make our text quite large we can Center it we can balance it and we can also make sure that it&#39;s a little bit Bolder by saying it&#39;s a font of semi bold give that a quick save and that should look pretty good as you can see down here and actually I don&#39;t really like that semi bolt so I&#39;m going to remove that I think it looks a little better without that now in order to make sure that everything is spaced out correctly I&#39;m actually going to come in here with a div that I&#39;m going to put all my content inside of and first thing I want to do is add the container class just to space everything out a little bit better that&#39;s at least going to give us a little bit of padding and margin on the right and left hand side and if we expand our screen you can see it looks relatively good we need to give some padding on the top and the bottom as well so we&#39;re going to come in here with a py of 16 that&#39;s going to give us a ton of space on the top and bottom of this we&#39;re going to say that everything in here is going to be flexed in the column Direction with a gap of 16 as well to really space things out and we&#39;re going to give even extra padding on the right and left so we&#39;re going to say PX of 8 but on larger screen sizes we&#39;re going to give it even more padding of 16 there we go so now everything should be super well spaced out make sure I do that like that and now we can work on creating a grid of all of our different logos because this you can see is essentially just a grid layout that scales as your screen gets larger and smaller so that&#39;s what we want to emulate as well so below our H2 we&#39;re going to have a div which we&#39;re going to give a class of grid by default it&#39;s going to have two equal sized columns on the medium screen size it&#39;s going to have three sized columns and then finally on the extra large screen size we&#39;re going to go all the way up to five columns cuz we have enough space to support that and we&#39;re going to have a nice big gap of 16 in between each different section now for our icons I could copy over all these different icons but instead what I decided to do is I decided to just use icons for the clerk and neon since they&#39;re sponsoring this video I figured that I should just throw in their icons so all I did is I took the actual SVG icons for them and I converted them over into a react component as you can see here this is the clerk SVG icon and if I come over to here I have the neon SVG icon as well if you want to be able to get these icons directly from react you can just come over to the GitHub repository Linked In the description and you can copy both of these different components over to your application or you can create them yourself if you want but I figured I would give them to you if you want to be able to use them so now I can come in here I can create a link tag so let&#39;s make sure we import that which an href that&#39;s going to go to either Clerk or neon in our case let&#39;s make this a link to Neon so we&#39;ll put neon&#39;s homepage inside there and then we&#39;re going to render out our neon icon component just like that so now if we give that a save and we come over to our application we should see we have the neon component showing up right there I can copy this down and do the same exact thing for the clerk homepage so this one is just clerk.com just like that and we can come over and render out our clerk icon there we go give that a save and now you can see our clerk icon shows up and I can just copy this down a few times to have 10 total icons so this is going to be 4 6 8 10 give that a save and now you can see I have 10 different icons showing up but obviously this last icon should be hidden when my screen is showing three icons cuz it kind of looks weird with this extra one so this final bottom icon I&#39;m going to have a class name on and whenever I&#39;m between the sizes of medium and extra large I want to hide this so I can say that I want to have this be a medium with a maximum of extra large and it&#39;s going to be hidden so between medium and extra large it&#39;s going to hide this last final icon so I give that a save and now you can see the icon is removed on smaller screen sizes you can see I&#39;m going down to two icons accidentally click the link to Neon there and if I zoom my page out and make it wider you&#39;ll see eventually I jump over to to five icons as well on a larger screen size so this is super mobile responsive and it&#39;s looking really great on all different screen sizes now we finished up this entire section and I could go through and build each one of these sections one to one from this homepage but honestly that&#39;s not the important part of this application so instead what I&#39;m going to do for the very last section as I&#39;m going to build out a pricing section because obviously that&#39;s something you need to have on pretty much any homepage and it&#39;s going to show us a lot of really important best practice clean coding things we can do which you&#39;re going to see the benefit of as we build out the rest of this project it&#39;s going to save us so much time so first of all I&#39;m going to give this an ID here of pricing just so we can actually link to this page there we go pricing so that way when I click this pricing link it&#39;s going to bring me to this exact section down here and if I put the text pricing in there and I scroll up click pricing you can see it brings me down to that page where the pricing text is at the bottom now for our sizing for everything I want to have PX of 8 and I want to have a py of 16 to give us a ton of space again and for this one I want to have a background of accent but I want it to be very light it&#39;s only going to be 5% of our accent color so it&#39;s just going to give us a very light bluish color it honestly might not even show up on the recording but as soon as we put a white card over top of it you&#39;ll definitely be able to see the difference between this very off blue color and the white card that&#39;s on top of it the next thing we want to do is to add in our heading so we&#39;ll come in here we&#39;ll add in what our heading is you can see my font size is going to be 4XL centered and balanced with a semi bold and some margin on the bottom so I give that a save you can see we get our nice pricing section header right there and then finally we can move on to our grid so this is going to be a grid we want to have two columns so we&#39;re going to say grid columns 2 but on a large screen size we&#39;re going to move up to a grid Columns of four in this because I&#39;m going to have four pricing tiers so it makes sense to either have a two column Grid or a four column grid for this and then I want to also make sure that I have some gaps in here so a gap of four the max screen for this is going to be extra large again so it doesn&#39;t get too large and we&#39;re going to center it by using MX Auto so we can bring that down now and all I want to do in here is render out all four my different pricing tiers but I want to be able to get this information in a place that I can reference all over my application so when I&#39;m doing things like permissions I can reference it whenever I want to render my pricing cards in a different location I can reference what are the things that each different tier can do so what I&#39;m going to do in my application here inside my source folder I&#39;m going to create a brand new folder called data and this is where I&#39;m going to put things that are constant things that never change inside my application I&#39;m going to create a brand new file called subscription tiers. TS make sure I spell that properly subscription tiers there we go and now inside here I want to write out all the information for each one of my subscription tiers now I&#39;m going to paste this down but I&#39;m going to go over exactly how everything in sear works so you can see I have this object with all my subscription tiers I have free basic standard and premium and I&#39;m including all the information I need for example what is the name of this how much does it cost in cense what is the maximum number of products the person can create what is the maximum number of times I can show the banner for the user and then what are their different permissions can they access the analytics can they customize the banner can they remove The Branding and then finally to link everything up with stripe I&#39;m going to add this stripe price ID for now we can just get rid of this section because we don&#39;t have stripe in our application we&#39;ll come back and add that in a little bit later but this is all of our different subscription tiers now I want to make sure I order these in the correct order so I&#39;m going to export another constant variable called subscription tiers in order I&#39;m going to set that equal to an array and what I can do inside of here is I can say I want to get my free tier and then I want to get my basic tier so we&#39;re going to have basic I&#39;m going to bring this down for my standard tier and then finally I&#39;m going to add in my premium tier as the last one so this is in order from cheapest to most expensive because that&#39;s how I want to show that I&#39;m going to set that as a constant variable cuz I never want this to change so now we have this file that contains all of the source of Truth for everything related to our subscriptions and how different things are handled and if we wanted to be able to update this and say you know what on the basic plan actually 20,000 people can view it we can change that in one place and it updates everywhere in our application even on our homepage I&#39;ll show you what I&#39;m talking about inside of here we can Loop through those subscription tiers so I want to just map through each one of those tiers and I want to render them out inside of a pricing card so I&#39;m going to say pricing card just like that we have the key be our tier just like that make sure I spell all this properly and I can make sure I actually get the subscription tiers in order because that&#39;s what I really need so now I can see I get all my information the name I know is unique and then I just want to pass along all my different information for my tier along to this pricing card which is a component I&#39;m going to create right inside this file so we&#39;ll say pricing card just like that now what I need to do is I need to specify all the different properties being passed along to this so for example I have a name I have a price in cents and I have all the other information that I&#39;ve determined that I need to have that I set inside this subscription TI file and take the type of this I can just say that this is going to be a type of it&#39;s going to be my subscription tiers in order and I want to get an individual one so we&#39;re going to say get a number from there so what this is essentially saying give me the type of what one of the elements inside this array is going to be and that&#39;s going to give me all of this information and I can use this inside my pricing card now just to show you that this is working I&#39;m just going to return the name directly from here and give this a quick save and if we scroll down you can see I get my names being printed out in order now we do have an error just cuz this is being imported it doesn&#39;t need to be imported and once we clean that up now all we need to do is render out what our pricing card looks like so to use the pricing card I&#39;m going to be using Shad CN and I&#39;m going to import the card component so let&#39;s get the card component imported from Shad CN so now inside of here I can render out a card directly from Shad CN and inside of there we&#39;re going to have a card header and inside of that we&#39;re going to have a card title and then also I&#39;m going to put a card description into here as well so for my card title this is just going to be whatever the price is so I&#39;m going to put a dollar sign and I&#39;m going to put whatever my price in senses times 100 there we go and I want that per month so now that&#39;s just going to render that out so if I look here you can see we get our prices right there now it looks like things are wrong because this should be divided by 100 there we go obviously I wanted to convert from cents to dollars not multiplying by 100 dividing by it now inside of my description this is actually where I want to put the information for how many visits they can show up on the page so this is going to be my Max number of visits put that inside of here and this is going to say pricing page visits per month give that a quick save and now you can see we get 5,000 10,000 a million and so on but that&#39;s kind of ugly I want to format this in a compact number way so I&#39;m going to create a function called format compact number just like this and pretty much anytime in your application you have code you know you&#39;re going to use in multiple places for example a formatter for formatting compact numbers I highly recommend breaking that out into its own file so in this lib folder I&#39;m going to create a formatters file so we&#39;ll say formatters TTS I&#39;m going to export a function which is called format compact number it&#39;s going to take in a number and it&#39;s going to format it in a compact style for me so up here I&#39;m going to say const compact number formatter is equal to intl. number format I want to get a new one of these I want to set the low cal to be undefined that way on where the user is coming from it&#39;ll show it to them in their actual local and then I want to specify the notation to be Compact and if we do that real quick let me just finish out what this function is going to be we just want to call format and pass in our number now if I import that into this file right here you&#39;ll notice it&#39;s going to take things like 5,000 and convert it to 5K 1 million is 1 M 100,000 is 100k it&#39;s just much easier to look at and read and again if we change our numbers it&#39;s automatically going to change our formatting for us now we also want to put the name of our product in here I&#39;ll put this inside the header at the top and for this one I wanted to have some distinct Styles so we&#39;re going to say the text is going to be our accent color so it&#39;s going to be that blue color we&#39;re going to say the font is going to be semi bold and we&#39;ll put the margin bottom of eight on this close that off and inside of there we&#39;ll put our name just like that so now if we give it a save you can see it says free at the very top which looks really good and we can even make our card title stand out a little bit more by making the text a little bit bigger so we&#39;ll say text extra large and font of bold so that our price really sticks out compared to everything else so that&#39;s our header completely done and now we can work on the content section so we can say card content I want to make sure that I import this file there we go and inside of here I&#39;m going to have a button for signing up so we&#39;re going to have a sign up button and inside of that I&#39;m going to render out a button component directly from Shad Cen so there we go and our button component is just going to say get started so now you can see I have a get started button right here but I want to change exactly how this looks for different pages so for my standard one I want this to be considered my most popular one so it&#39;s going to have like a fancy styling and coloring to make it look a little bit different so what I can do here is I can say const is most popular is equal to and let me make sure I spell this right const move it up here so if the name is equal to standard then it is the most popular so if we&#39;re the most popular one I want to change my variant so is most popular it&#39;s going to have one style otherwise it&#39;s going to have a different so by default I just want to use my default style otherwise I want to use my accent Styles but by default there is no accent variant inside of shad so we need to create our own accent variable which is going to essentially change it so we&#39;re going to have a background of accent so all I want to do is change my background here to Accent I want to change my text to be accent essentially so we can say text accent foreground just like that I want it to have a shadow I also wanted to have a hover where its background accent and essentially I want to change that to a 90% opacity so essentially it&#39;s the exact same thing as our default but I changed everything to accent so now we should have a purple button for our accent button let me just make sure everything else is working good is most popular should be working for our button give that a save and now you can see we have a blue button for our standard button I also want to change our Styles a little bit so we&#39;re going to come in here with a class name I&#39;ll make my text a little bit larger make the width full width and I&#39;ll make it a little bit more rounded so we&#39;ll say rounded of large so now we have this big button that&#39;s essentially saying hey get started in bold letters that&#39;s the call to action for our page now the final thing that we need to do that we have our sign up button done is to finish up what our card content is going to be and that&#39;s going to be inside of our card footer that&#39;s where each of our different featur feat is going to go I&#39;m going to create my own component for those cuz this is something we&#39;re going to have repeated everywhere in our application so a feature is going to be really basic it&#39;s just going to have a child and it&#39;s going to have a class name just like that and I want to make sure that I actually give this some Styles so we&#39;ll say children is going to be a react node and then we&#39;re going to have our class name which is an optional string that we can pass into here let me make sure I have all that spelled out properly there we go that looks like it should be good import react node and now we just need to use that information so we can return here a div which is going to have all my different classes and I want to have a check icon so we can say check icon just like that that&#39;s going to be that check mark that we want to show up so for this one I&#39;m going to have a size of four I&#39;m going to specify my stroke as an accent color and the background is going to be the same thing but with 25% opacity I&#39;m going to make it a full circle and I&#39;m going to give it a very very small amount of padding of 0.05 just like that so now we have our check icon showing up I can look at what this looks like by just rendering out a feature just like this and I need to pass it along some really basic information for example whatever I want my children to be that&#39;s going to be some text that I&#39;m going to render inside of its own span right here there we go so give that a quick save and you can see we have our check mark with some text showing up obviously I want this to be side by side so I&#39;m going to use some class name information right here and for this I want to use the CN library that way I can combine for example my Flex item Center and GAP 2 class with the classes that I passed in that are custom in case I need any custom classes so now you can see that lines these up side by side and I can also pass in custom classes if I want so now let&#39;s go ahead and create all of our different features first of all I want to style this a little bit inside my card footer so I&#39;m going to say class name which is going to be a flex column with a gap of four and the items are all going to be in the start just like that so now if I have multiple features you can see they&#39;re spaced out from one another now what I want to do is I want to have this first feature be for the maximum number of products they can have and I want this one to be bold so we&#39;ll say font bold just like that and inside of here I want to take my max number of products and then after that I just want to put the text products give that a quick save now you can see if I look down here and I make sure to actually refresh my page that you can see it says one products five products 30 and 50 now obviously I want to get rid of the s in the case that I have one product so I&#39;m going to add a little bit of extra styling into here so I&#39;m just going to say if my max number of products is equal to one then the text is going to be product otherwise my text is going to be products now if I give that a save you can see it says one product or going to have an S at the end for all the other different quantities so now let&#39;s go ahead and get the rest of my features implemented so we&#39;re going to have a feature here and this feature is going to be the ability to have PPP discounts this is something every single tier has access to and now for the rest of these features I just want to check hey can I customize the banner well if so then I want to have a feature that says Banner customization there we go so now you can see that only the tiers that have the ability to customize the banner which is the standard and premium show that particular feature I can do the same thing here for if we can access the analytics well I want to add in advanced analytics give that a quick save and now you can see only the ones that have access to analytics have that information and I&#39;m actually going to bump this up one just so it shows up over top the banner customization and I&#39;m going to paste this down one more time and this is going to be for anyone that can remove branding so we&#39;re going to say can remove branding and this is saying remove easy PPP branding there we go so so now anything that has the option to remove our branding which are these particular ones can do that and again I&#39;m going to move this all the way up here right by the analytics there we go so now all these tiers have analytics and can remove The Branding and only these ones can customize the actual Banner so as you can see now even on larger screen sizes we have a really nice and robust looking pricing system and the best part is let&#39;s say I go ahead and I&#39;m like you know what I want to change how my different tiers work well I can go into here and say you know what the free tier now is actually going to be 10 products give that a save boom it automatically updates everywhere in our application that&#39;s why I love having these data files that contain all of our static data now the final section I want to work on is pretty much a section that almost every site has which is just this really large footer section right here as you can see on parody deal site so I&#39;m just going to create our own version of that let&#39;s scroll all the way up here and create a brand new section but this one is going to be a footer because obviously it&#39;s the footer of our application I want to add a class name here of container to contain it in a size I want to have pading top of 16 padding bottom of eight we&#39;re going to make it a flex but on a small size it&#39;s going to be Flex column again make it mobile responsive we&#39;re going to have a gap of eight except for on small screen sizes we&#39;ll have a gap of four between all of our different sections we&#39;ll justify the content to have a between and we&#39;ll say the items are going to be at the start so now we can go ahead and actually put all of our information inside here which has two distinct sections the first is going to be a link which is going to go to our homepage and that&#39;s going to use our brand logo so we&#39;ve already used our brand logo once so again this is why we created a component for that so now down here you can see we have our brand logo in the footer then we&#39;re going to have a section which contains all of our different links so we&#39;re going to come in here it&#39;s going to be Flex it&#39;s going to be in the column Direction and on the small sizes we&#39;re going to put them in the row Direction otherwise we&#39;ll have a gap of eight and if we look back at the parody deal site essentially I want to have all these different groups you can see here I have a group with all these links I have another group with all these links and another group with all these links that&#39;s what each of these divs is and for each of these divs inside of there I need to have a div for the actual footer links so what&#39;s come in here I&#39;m going to create a div class name flex and flex column with a gap of eight that&#39;s going to be if we come back to here again for each of these individual sections so this very first Dev I created was for all the sections combined together and this each individual div inside of there is for each of the three different columns I have so we can come back into here scroll all the way up so this div right here is for our column and I&#39;m going to create a separate component for this called footer link group and this footer link group is going to have a few things it&#39;s going to have a title in our case this will say help and then it&#39;s going to have our links and the links is going to be an array of objects where we&#39;re going to have a label just like this for example this one we say PPP discounts and then it&#39;s going to have an href in our case all of our HS are just going to be empty like this and if I make sure I clean up my code by putting these brackets in place give that a save you can now see we have our first link showing up I&#39;m going to put this on one line so it reads a little bit better there we go and I&#39;m just going to copy this down because we&#39;re going to have two links inside of here give that a save and let&#39;s change this one to a discount AP there we go and now we just need to create this footer link group so all the way down here function footer link group and we know that it&#39;s going to be taking a title that comes inside of our props and it&#39;s also going to be taking our links now if we type these out our title is a string and we&#39;re going to have our links which is going to be an object which is a label which is a string an href which is a string and we&#39;re going to have an array of those there we go and now we can render out what this group looks like so the first thing is I need a div to contain all of them and we&#39;re going to have these be in the column Direction with a gap of four between them then the next thing I need to do is to put my header which I&#39;m going to use an H3 for so we&#39;ll say H3 close that off and this is going to be whatever that title for my group is going to be and I just want to give it a few Styles so we&#39;ll say class name font of semi bold there we go the next thing I&#39;m going to want to do is to have a list which contains all my information and for this list I want it again to be in the column Direction but with a smaller Gap so we&#39;ll use gap of Two And even some smaller text then we&#39;ll Loop through each one of our links so for each link what I want to do is I want to render out An Li since we&#39;re inside of an ordered list with a key that&#39;s going to be link. href because that&#39;s the only thing that&#39;s going to be the same or guaranteed to be unique then we&#39;re going to come in here with a link and this is going to be an href which is my link. href and the label for this is link. Lael relatively straightforward so now if we give that a quick save we make sure that everything that we need for this footer group is like it should be so footer link group footer link group we have title we have links everything should be good we&#39;re getting an error though oh and that&#39;s just because I need to make sure I return our jsx from here so now back to our application scroll down to the very bottom and it looks like this is not rendering out like we wanted to let&#39;s make sure we save still not showing up my guess is inside of here I didn&#39;t render out something properly looks like all that is proper so that should be working my next guess is related to caching I&#39;m just going to do a hard refresh and there we go it was related to caching so we have our information showing up and if we go to a larger screen size you can see it&#39;s still working but obviously looks like our Flex is actually swapped you can see on small screen sizes it shows up side by side while on large screen sizes it shows top to bottom so we have something swapped with our Flex so if we go ahead and we look at our footer here this is where we have our Flex swapped on the small screen sizes we should have a flex of row so let me change that to row and normally we should have a flex of column that should hopefully fix that so you can see on a small screen size it&#39;s stacked like that and a larger screen size it stacked side by side now what we need to do is just to finish out the rest of our footer link groups so inside of here the next section I have is for Solutions so you can see we have our help and solution stacked on top of each other and now I essentially just need to copy this section multiple times so instead of making you watch me actually typ this information out I&#39;m just going to come in here and I&#39;m going to copy it over for you because it&#39;s again exactly the same if I copy this down you can see if I minimize it this is the exact same style and inside of here we just have footer link groups with each of our different links so if I give that a quick save you can now see all of our links are showing up and when we shrink down to a smaller screen size you can see they stack vertically like this and that just because we swapped everything to flex column on the smaller screen sizes so there we go that&#39;s our entire homepage entirely done for our application and it looks relatively good obviously you can make different changes to this and it looks a little bit zoomed in right now cuz my screen size is very zoomed in but on a more normal screen size this looks even better than it does on this more zoomed in screen size now the next thing that I want to work on now that we&#39;re done with our homepage is to work on our sign in and sign out workflow right now it works just fine but you&#39;ll notice in our URL bar it actually redirects us to a different site that&#39;s because we haven&#39;t set up our own signin and sign out pages so we&#39;re going to do that next and with clerk it&#39;s incredibly easy to do all you need to do is to create a folder for sign in and sign out and I&#39;m actually going to put that inside of its own group called off again just to keep things separated and so I can use a single layout file which we&#39;ll create now for both of our different off pages so to create your own sign-in sign out workflows just create a folder called sign in make sure you spell signin properly there we go and inside that folder you need to create another folder for a catch all so this is going to be double brackets triple followed by the text sign in and again close that off with a double bracket and then inside of here just create a page. TSX now you would think we have to write out a bunch of different code for creating our own signin page but clerk has a component for us that we can use so we&#39;ll call this sign in just like that make sure it&#39;s a default function and I&#39;ll call it signin page and that&#39;s because the component we&#39;re going to be using is just called sign in all we have to do is just import that component and our signin page is entirely done now I&#39;m going to copy the exact same thing for sign up so make sure that we call this sign up just like that we&#39;re going to name this to be sign up so it&#39;s the exact same thing but instead of sign in we use sign up let me just make sure I restart my server that should hopefully fix that there we go and now inside of our sign up page we want to use the sign up component from clerk so let&#39;s get that and rename this to sign up that&#39;s how easy it is to get working with that now the only other thing I want to do is to create a layout so we&#39;re going to say default function and that&#39;s going to be our sign or actually our off layout and to save us some time I&#39;ll just copy the code over for this all we&#39;re doing is we&#39;re making sure it fills the full screen and it positions everything in the center as literally the only thing that this does so now when we go to our signin page we should hopefully see that it&#39;s centered in the page and it goes to our own URL but you&#39;ll notice it still goes to this clerk URL that&#39;s because we have one more step that we need to finalize and this is telling clerk that we created these brand new sign-in Pages for it to use to do that all we need to do is go into our environment variables here where we have our other clerk information I&#39;m going to come down and we&#39;re going to paste in this next public clerk signin URL and the same thing for sign up URL and point them to our new signin and sign up page that&#39;s all you need to do so now when I click on the login button for our page give it a quick refresh everything works click on login you can see it redirect me to my own Local Host 3000 things are much more zoomed in because I&#39;m zoomed in on my current page and you can see we&#39;re on our own URL which is really really great now a few more cleaning house things that I want to do before we start working on our dashboard is you&#39;ll notice that we have a lot of environment variables it&#39;s hard to keep track of these environment variables especially when you clone your code for a brand new time so I&#39;m going to create a brand new file called env. example this is going to be essentially a list of all of our different environment variables with sample values for anything that we can keep in there for example our sign in and sign up URL we don&#39;t want to change that so we&#39;ll keep those in there but our secret keys that we have here we&#39;re going to keep those hidden so I&#39;m going to make sure that those are completely empty now when someone pulls down this code brand new they&#39;ll have this file to give them an overview of what our different environment variables look like I&#39;m also going to label this to say that this is our clerk environment variables and when we move to other environment variables we&#39;ll put them in their own section I&#39;m going to do the exact same thing inside of here put our clerk environment variable label so now we know that these are all clerk related environment variables this just helps with people in the future downloading our application and using it so now let&#39;s open up our dashboard and create a layout file for us to use we&#39;ll say layout TSX and we&#39;ll create a page and this page for now we&#39;ll say default and that&#39;s going to be a function dashbo page for now is just going to have nothing inside of it just so we have something there to render and then here export default function and this is going to be our dashboard layout make sure here that I spell layout properly and inside of this dashboard layout we&#39;re going to be getting our children in here so we&#39;re going to say children and that is a react node there we go and inside of here I want to create a div to wrap everything and that&#39;s going to have a background of accent and that&#39;s going to be at that color five again opacity of five so it&#39;s very very faint but it makes it so that white will really pop and we&#39;re going to make it so that it&#39;s at least always the same size of our screen that way that blue background covers our entire screen now inside of here we&#39;re going to render out a Navar but we&#39;re not going to get the nav bar from our marketing folder instead we&#39;re going to create our own nav bar specifically for our dashboard pages and then lastly I&#39;m going to have a div that contains all of our different children I&#39;m going to give it the container class and some padding on the top and the bottom and we&#39;ll put our children directly inside of there give that a quick save make sure I return this and now we at least have our dashboard and if we just comment out this nav bar for now when we go to our dashboard for example slash dashboard and go enter you can see we just get that blank page with that slight blue background now I&#39;m going to go ahead and work on creating our nav bar next so let&#39;s comment this in and to do that I&#39;m just going to create a brand new folder underscore components and this is where we&#39;re going to put the components that are specific only to our private dashboard pages so we&#39;ll come in here export function nav bar this nav bar has no components that it takes in and we just want to render out a header kind of like we did before inside of here we&#39;re going to have a nav and inside of here we&#39;re going to have a bunch of different links so the very first link I have is going to be for our main page so we&#39;ll say class name that&#39;s going to go to our dashboard there we go and it&#39;s going to make sure oops this should actually be our href not our class name there we go and for our class name name this is going to be where we put our margin right on the auto so now let&#39;s make sure we import our link just like that and inside of here we can put whatever we want and in our case we want to put our brand logo again so let&#39;s just get our brand logo render that out and again let&#39;s go to our dashboard page make sure I go to that page and you can now see hopefully at the top of our page if we make sure that we have this imported properly give that a quick save you can see we get our logo at the top when we click on it it brings us to our dashboard page now obviously I want to style things so it looks a little better so we&#39;re going to come in here make this a flex container py of four to give it some spacing again we&#39;ll give it a shadow this will be a more neutral Shadow and we&#39;ll make it a background color of white essentially which is our background right there also for our nav I&#39;m going to make this have some Styles so we&#39;ll say class name here is going to be Flex we&#39;re going to Center the items in here and we&#39;re going to give them a gap of 10 and finally I&#39;m going to make this a container just to give us some padding and make everything look a little bit better so now we have our first link let&#39;s move on to our next link right here and this link is going to be for dashboard SL products and you can guess that this will say products inside of it and we&#39;re just going to copy this down a couple times because we&#39;re going to have our analytics and we&#39;re also going to have our subscription that we&#39;re going to manage Subs whoops subscription there we go and then finally we want to be able to have a button for managing our user profile clerk makes this super easy by giving us just a user button component we can import we don&#39;t need to do anything else just give that a save and now you can see we have this user button over here just give it a refresh make sure it shows up properly and actually the reason that nothing is rendering over here is because right now I&#39;m on this page but I&#39;m currently not signed in we don&#39;t have any authentication set up which is a huge problem so we need to go over to our middleware and actually set up this authentication so inside this middleware this clerk middleware function is where we make sure we protect the pages we want to protect so this function actually takes another function as an argument and in this function that we&#39;re passing into it takes an off as well as our requ EST information so if we want we can call off. Protect and what that&#39;s going to do is make it so that you must be signed in to view this page but we only want to protect the pages that are private so to do that I&#39;m going to actually create a variable called is public route this is going to be a function just like this and I&#39;m going to be using the create route matcher function which comes directly from Clerk and this allows us to pass in essentially the same thing we pass this matcher down here and it&#39;s going to match okay if this page is matched then it&#39;s going to be a public route versus not so just want to put in here a list of all the pages that are public so our homepage is going to be public also our sign-in pages are public so we can say sign in and by using this dot with a star inside parentheses this says anything that comes after signin also counts so if we go to slash signin SL something else it&#39;ll still be marked as public now I want to do the exact same thing for our sign up page so I&#39;m going to come in here with sign up and then finally we&#39;re going to have an API for this application so I&#39;m going to put our API in here as public as well because that&#39;s how people show the banners on their particular pages so now we can use this by saying if it is a public route or if it is not a public route sorry passing our request well if we don&#39;t have a public route then we should probably protect that route so now if we&#39;ve done that and we give our page a refresh over here we should see we get redirected to the signin because we are on a page that is currently public so let&#39;s just go back to our actual Local Host right here and what I want to do is I want to click that I want to log in or get started so we&#39;ll say get started for free because I need to sign up I&#39;m going to create an account using GitHub so we&#39;re going to use my GitHub account give that a quick sign in I&#39;ve obviously already signed in before with GitHub so it just worked perfectly out of the box but it redirected me to the homepage I want to redirect to the actual dashboard I don&#39;t want to have to click on this link to get there I just want to be automatically redirected to that page luckily with clerk this is incredibly easy and again it&#39;s just a couple environment variables so I&#39;ll paste these down for you you can see that they are the next public clerk sign in or sign upore Force redirect URL and this is just saying redirect people to this page after they sign in or after they sign up so now let&#39;s make sure we add those to our example environment variables as well so now if I just sign out of my application I&#39;m on this normal dashboard page and I click that I want to log in log in with GitHub and you can see it&#39;s going to redirect me to the dashboard when I&#39;m done signing in which is super great so now we have our authentication essentially ironed out we really don&#39;t need to change anything at all the very next thing that I want to work on is to be able to get our database set up because we really can&#39;t do anything on these dashboard Pages unless we have a database set up so to get our database set up we&#39;re going to be using drizzle I absolutely love it and you&#39;ll see in this video especially how amazing drizzle is compared to something like Prisma because of the flexibility we get so to get started with Drizzle we&#39;re going to be using it with neon which again they sponsor this video they&#39;re amazing for database provider hosting all we need to do is copy over this code right here and we need to paste it down to import all these different libraries then you can see down here we have the code right here that we need to import into a particular file to get started with Drizzle so I&#39;m just going to copy that code create a brand new folder called drizzle and inside that I&#39;m going to create a folder called db. TS which is where to paste in this code right here and I just want to make sure I export the information I need so here I have this constant called DB I&#39;m just going to export that from this file so that gives me access to my database now I&#39;m going to call this just my database URL just like this from my environment variables so I&#39;m going to come into my environment variables we&#39;ll create a section at the top here for our database and we have a database URL we need to set it to some specific string also I want to make sure I put this in my environment variable for the example file as well so people know they need a database URL now to get a database URL we&#39;re just going to set things up on neon so I&#39;m going to come over to Neon all we need to do is give our project a name we&#39;ll call this easy PPP we&#39;re going to give our database a name easy PPP is fine and we&#39;re going to say create this project just that easy you can see the really nice thing about neon is I have the ability to branch which means I have my production database right here and I can create a development database just for me click this one button now I&#39;m working on my own production database now I&#39;m going to just make this a full screen because this works better this way and what I want to do is I want to actually connect to this particular database so the easiest way to do that is I could just copy over this string or I could come over and I can make sure I&#39;m doing this properly by going to this overview Tab and I click on this connect button right here for this particular database I want to make sure that I&#39;m on the branch that is correct I&#39;m on the main branch I want to make sure I navigate to my Kyle Branch here and then I click connect and I want to make sure I use a pulled connection the reason for this especially if you&#39;re dealing with production is that if you have something that&#39;s going to be produced on the edge which neon is great for Edge databases it&#39;s going to make it so that you actually have enough connections because a lot of times databases only allow you like five different connections and if you&#39;re using something serverless on the edge you&#39;re possibly going to have hundreds or thousands of connections so this is just going to make sure that your database will work flawlessly on the edge so we&#39;re just going to copy over this database URL and that&#39;s all we need to do from neon to get this started and working so let&#39;s come over to here make this a little bit smaller so it&#39;s easier to work with and paste down our database URL into here and now we should have everything we need to get started working you&#39;ll notice we have a little bit of an error in here that&#39;s because this database URL could be undefined it doesn&#39;t know we could say you know what I guarantee this is going to be a string typescript type this and that&#39;s going to work fine but if someone forgets to import their database URL they&#39;re going to get a weird error because it doesn&#39;t have a database URL to connect to so I&#39;m actually going to go ahead and I&#39;m going to set up a file for all of our environment variables and I&#39;m going to do that using the T3 environment variable package so what we can do is we can install this package npmi this is T3 environment DJs this is going to make it really easy for for us to have type safe environment variables we also need to make sure we have Zod for this so I&#39;m going to npmi Zod as well to do all of our different validation so now that we have that done we can go ahead in our data folder and I want to create a brand new folder for my environment variables and I&#39;m going to have them for my client and I&#39;m also going to have them for my server just like that you can combine these together but I like to keep them separate to be really distinct which one&#39;s are client and which one&#39;s our server now the documentation for getting this set up is incredibly easy to understand and use all we need to do is export what we&#39;re going to put our environment variables in we&#39;re going to call this EnV and that&#39;s coming from create EnV just like that and this takes in an object the first thing you want to Define is empty strings as undefined that way if you pass in for example something that&#39;s completely blank it&#39;ll convert that to undefined which is probably what you want next we want to Define what all of our server environment variables are since we&#39;re in our server. TS file so I have a database URL just give it the exact same name you used before and then for our validation we know that this is a string and we know it is a URL so let&#39;s make sure we import this from Zod just like that so we&#39;re saying this is a string from Zod and the last thing we need to do import is going to be our runtime environment there&#39;s also an experimental runtime environment which is what I&#39;m going to be using because it allows you to just pass in process.env for all your server environment variables and it&#39;ll hook up everything for you if you use the normal runtime you actually need to manually say that our database URL is equal to process. env. database URL this is kind of a clunky amount of code to write which is why I think it&#39;s much better to just use the experimental version like like this which works great for our server now for our client it&#39;s going to be slightly different we&#39;re going to paste this in and instead of server this is going to say client here and every single client variable obviously must start with next public underscore whatever our variable is going to be so if we come into our environment variables we have all these different environment variables I&#39;m going to copy them over so we know what the names are come into here going to put them down just below so we have our clerk publishable key we know that this is going to be a string just like that I&#39;m going to copy this down to few times cuz we have all these other variables so we have our redirects let me make sure I get those we have our sign up URL and our sign in url all of those are going to be strings and they&#39;re all required now the unfortunate thing about the experimental runtime is you actually need to pass it in everything for your client side code so I must say that for example my public key here is equal to process EnV do and whatever I call that variable which is just the exact same name I need to do this manually for every single one which is a bit of a pain so I&#39;m just going to copy this down make this a little wider so it shows up on one line for you and I&#39;m just going to paste the correct names down for both of these there we go one more to go and there we go that cleaned up all of our different errors so now we have everything hooked up for all of our different environment variables I just want to make sure I get my last environment variable in here which I believe is called clerk secret key there we go clerk secret key and this one is a string there we go that&#39;s everything we need so now we have type safe access to all of our environment variables so back into here what I can do do instead of just getting my variable directly from process. EnV I can say EnV make sure I get my server variables and now I have typesafe access to my database URL and if for some reason I don&#39;t include my database URL I&#39;m going to get an error when I try to run my application for example I&#39;ll just completely remove this and show you what I&#39;m talking about give this a quick save it&#39;s going to reload everything and now if I try to access anything in my application that uses that database URL it&#39;ll throw an error now right now I&#39;m not accessing my database URL but you would see myself get an error if I did try to access that information for example if my Seeker key was empty then I would get an error when I tried to deal with logging in information and so on so like if I try to sign out I may get an error if I try to log in I may get an error but again I&#39;m not seeing any of these errors showing up because I&#39;m not using those particular variables but as soon as I use them you will see those errors now to finish our setup for drizzle we need to also create a new file called drizzle. config.sys config I said my schema is in this folder I say all my migrations are going to go into a folder called migrations in my Jal folder everything is going to be postgress strict true and verbose true just make it so when you do migrations it&#39;s going to give you extra warnings and validation on what&#39;s going on and then finally I&#39;m actually seeing my database credentials right here inside of this so now I have all my stuff hooked up and again I&#39;m using that environment variable that I created on the server so now we need to get started with our database configuration which is all going to happen in this schema file so let&#39;s just go ahead and the first thing I want to do is export a constant variable called Product table and we&#39;re going to set that to PG table just like that from r o RM and then we can give it all the different names in columns so the first thing is we need to give it a name we&#39;re going to call this products just like that and we&#39;re going to give all of our different columns inside of here so for example I&#39;m going to have an ID column with a uu ID set it to ID just like that and we&#39;re going to say we&#39;re going to have a primary key default that to be a random uu ID also each of our products is going to be linked to a user so we&#39;ll give it a clerk user ID which is going to be a text field clerk user ID and we&#39;ll set that equal to not n there we go and make sure again that I import this text field directly from my PG core because we&#39;re using postgress we need to use the PG core now there&#39;s a few other columns that I want to have inside of here so I&#39;m going to paste these down a name which is a text which is not null description which is a text that can be null and then a URL that again cannot be null I&#39;ll even put it above my description so all our not null stuff is up there then I want to have a created at and updated at but I&#39;m going to put these on like every single field I have so what I&#39;m going to do just going to copy these over again is I&#39;m going to create a variable called created at and updated at which are going to be timestamp variables and they&#39;re going to have a time zone associated with them generally in postgress if you&#39;re dealing with timestamps you want to add a time zone in there it&#39;s not going to change your database by taking up more space is just going to make it easier to work with your times in the future and again let&#39;s make sure this is created at and updated at our created at field is not null and it defaults to whatever the current time is whenever we add it same thing with updated at and whenever we updated it it converts the time to the actual current date so it automatically updates that date field for us so now we have our product table completely done now the next thing I want to do on this table is I actually want to add an index indexes are really important if you&#39;re working with data where you need to access data based on specific fields for example I&#39;m almost always going to be getting my products based on this clerk user ID so where clerk user ID equals 1 2 3 and so on so I want to set up an index on this clerk user ID so that way it makes those queries even quicker than before that&#39;s what indexes are useful for so here I&#39;m going to say that I&#39;m going have a clerk user ID index I&#39;m going to use the index property from the PG core I&#39;m going to give it a name which is products. clerk user ID index and then finally I want to say what table that&#39;s going to be on which is our table. clerk user ID so I&#39;m just setting up an index on that particular Row in our database to make our queries on our product table using that row much quicker now the next table that I want to work on is going to be the customization table because I can customize what the banner looks like I need to have a table for storing that information so I&#39;m going to have a product customization table this is going to have an ID it&#39;s also going to have a class prefix this is like what I put before my CSS and this is the only thing that I can have be null because I can also not have a class prefix I need to have a product ID so that&#39;s not null and it&#39;s going to reference my product table and by putting on delete of cascade that means what&#39;s going to happen is if I delete my product it&#39;s going to delete the customization associated with that as well I also marked this as unique because each product can only have one customization table for it so each product has one row in the customization table so by making this unique it enforces that actual thing now the rest of this information is just all the different things that I can customize for example I can customize what my message is I can customize background color text color font size Banner container and whether or not this is going to be sticky to the top of the page and for each of them I gave them a default value so they all have default values so even if person does no customization they&#39;re going to have something that will display on the screen with all these defaults and then finally are created at and updated at Fields down there now the next thing we need to do with Drizzle is to set up a relation between our product and our product customization this will make doing certain queries much easier in the future so we can export a const called Product relations and we can set that to relations just like that again make sure we get that from the OM on our product table so these are going to be all the associations for our product table and this is going to take in a function just like this and this function takes in two parameters which is going to be either a one or a many so depending on if you have a one to one or a many to many or many to one relationship you Define that using this right here and this is going to return to us an object so let me just wrap this in some parenthesis there we go and the first thing I want to have is my product customization just like that that is a one toone relationship where each one of these has one product customization so I&#39;m just saying my product table has one product customization in it and I call that product customization let me make sure I got enough parentheses to close everything off and you can see that that works fine now I&#39;m going to copy this down here and this is going to be for my product customization relations there we go so product customization relations this is on my product customization table and again I can specify whether I have one to one or many to many in this case I only have a one: one relationship and I have one product so this one product is on my product table and I also need to specify a few different things because whichever table has the ID you need to specify a few other things on that relationship I need to specify what the fields are so in my case I have a product customization table. product ID the fields just references okay what field am I using for my foreign key in that case it&#39;s my product ID and then the referencing section says okay what does this reference in the other table well this references my product table ID so this just allows me to create really easy join queries between these two tables CU I know what the relation between them is now if we go back to my homepage so we can look at the pricing section you may remember that specific tiers have different abilities for how many times you can view the pricing page this is how many times the product can have Banner show up so we need a way to be able to track how many times each page has been viewed and then also use that information for analytics so the next table that I want to create is going to be the product view table and the product view table all that&#39;s going to do is it&#39;s going to be okay which product am I viewing and which country am I viewing from which is a table we&#39;re going to create in a little bit and then when did I actually view that so this when information is very useful for our actual analytics this country information is very useful for we analytics again so we can see where is everyone coming from and then obviously the product is very very important so we can associate how many times has each individual product been viewed so we can make sure we limit how many pricing page visits we have per month so that way we can make sure people upgrade from the free tier and so on to earn us more money so as I mentioned this uses a country table so let&#39;s create a country table here this is relatively straightforward all it has is a name and a code which again we&#39;re making sure that these are unique and we&#39;re giving it a country group ID which allows us to group our different countries together because when we edit our coupon codes we have the ability to view all the different groups for our coupon code so for for example all the people in the group with 20% purchase power versus 30% versus 40% versus 50% if you remember that edit page where it had all the flags that&#39;s exactly what each group represents so each country belongs to exactly one group so let&#39;s go ahead and we&#39;re going to create our group as well so we&#39;re just going to paste that down into here and then finally that should be the last thing we need for getting all the different stuff for these tables Associated so we have our country name code and group and our group all it has is a name and it has a recommended discount percent this is just helping people that are starting up creating their first product they don&#39;t really know how much of a discount to give for each different country so this says okay for these countries we recommend around a 50% discount or so on obviously they can change it but this just helps make their life much easier so again we have our groups we have our countries we have our product views and we have our customizations and our products now this still isn&#39;t nearly enough to get everything done but now we can set up the relations between all of these different things for example on our product we now have relations to other things namely we can have a bunch of different views for our product product so we have a many relationship that&#39;s on our product views so there&#39;s many product views that are associated with the product view table there we go now if we move down to our product view we need to create the relations for this as well I&#39;m just going to copy this over because it&#39;s relatively straightforward code we&#39;re creating a on toone relationship where it has one product and one country and we&#39;re using these ID fields for those references then we can move on to our country which again is very similar and rather straightforward you can see here our country is going to have a single country group group and it can have many different views in our product view table finally we have our country group relationship which again is going to be rather straightforward each country can have multiple different country groups now you&#39;ll notice in here we also have this section called country group discount so the way that I&#39;ve structured our database is we have a country and each country has a group that it falls in so this is whether it&#39;s going to be parody purchasing group of like 2 to three or 3 to four or four to 5 and so on and then each of those groups we can give a specific discount code too in our application so that&#39;s where this next table is going to come from it&#39;s going to be associating all of our different discounts for an individual group for an individual product so here if we take a look at this particular table you can see that this table has a country group ID which is going to reference our country group table it&#39;s going to have a product ID to reference our product table and then we have what our coupon code is as well as what our discount percentage is going to be so this is where the individual user saves a particular coupon and a particular discount percentage for a particular country group so this way if I want people in India and all other countries in that group to have 30% off using the coupon India I can put all that information in here and save that also I made sure that the primary key for this table is just my country group ID and my product ID because there&#39;s no way that I can have multiple entries for a individual product and individual group ID I can only have one coupon code and one discount percentage for this combination information so it made sense to make this my primary key I can also go ahead and set up My Relations so as you can see here my group discount relations is going to have one product and it&#39;s going to have one country group again based on these particular IDs I also can modify our product relation at the very top of our page because now we have another many to many relationship that I need to De with and this is my country group discounts which is going to be a manyu relation on my country group discount table now the final table that I need to add to my database is going to be for handling my subscription so are they on the free tier the basic plan standard premium and so on I need all of that inside of its own table so this table right here has a clerk user ID so I can associate it with an individual user it&#39;s going to have information related to stripee so I&#39;m going to have the stripe subscription item the subscription ID and the customer ID this makes it so that I can let the user change their subscription between different tiers without making them have to sign up for multiple subscriptions it&#39;ll automatically change one subscription to the next without like canceling or restarting it&#39;s important that you store all this information for subscriptions then we have the tier that they&#39;re going to be in which is going to be an enum I&#39;ll create in just a second so for example are they the standard the premium the basic or so on and then I have a few different indexes again to make my queries easier because I&#39;m always going to be creating this table based on either the user or the stripe index so that&#39;s why I have those different tiers now let&#39;s create that index or that tier so we&#39;re going to say cons tier enum equals and that&#39;s using PG enum just like that and we&#39;re going to call this tier and what I want to do for this is I want to get it based on all of my different subscription tiers so I have my subscription tiers just like this but I want to get just the keys so we&#39;re going to say object. keys just like that that&#39;s going to give me all of my different keys for this particular your user but this is just going to be an array of strings it doesn&#39;t know typescript isn&#39;t smart enough to know that this is specifically just the names of my tiers so I need to say that this is actually going to be an array of tier names so to do that I&#39;m going to create this tier names type so we&#39;ll say up here type tier names is going to be equal to all we&#39;re going to do is take the type of my subscription tiers and I want to get the keys of that so now if I hover over this tier names you can see it&#39;s free basic standard or premium so let&#39;s export that type just like that and now inside of here if I import that tier names that&#39;s smart enough for postgress to now know and drizzle to know that hey I have this information if I hover over this tier enum you can see it&#39;s either free basic standard or premium and that is absolutely everything set up for my database now I know I went through this rather quickly but that&#39;s because it&#39;s a lot of typing of code and overall the important thing is to get the high level of how the database works so I&#39;m going to go through that real quick first a user can create a product and this product has the ability to be customized through our product customization table and we have the ability to have specific discounts associated with that product using our country group discount table now we only can put discounts for individual country groups so instead of putting a discount per country itself we put a discount for each group of countries so that&#39;s why we have this country group table and this country table to make sure we track okay which group is each country in and we can easily change what group a country is in based on how the economy in that country changes over time for example if India all of a sudden gains a lot of wealth and a lot of purch in power for individuals increases in India India may move to a different pricing tier and nobody in our application needs to do anything we can just move that country from one tier to another and it&#39;s automatically going to work everywhere else now we also have a table for tracking how many times a product has been viewed which allows us to make sure that we&#39;re not showing the product more than they&#39;re paying for and we can show different analytics to our user finally at the very bottom we have the ability to store which tier a user subscribed to so that way we know are they on the free tier the basic tier the standard tier and so on so we can give them different permissions and allow them to use different things in our application based on what tier they&#39;re a part of so now once we have our schema entirely done we can go back to this drizzle file here and we need to make sure that we pass along our schema into this particular section of drizzle so let&#39;s import Star as schema from our schema file this is just going to make sure that drizzle knows what our schema looks like so we can do something like dbquery Dot and it&#39;s going to give us all the different tables we&#39;ve created and it allows us to do all the different relationships between them and so on it&#39;s really important that you do this otherwise you won&#39;t get any type safety now to work with Drizzle we need to run a few different commands so what I&#39;m going to do is actually go into my package Json and I&#39;m going to create a script for all the different commands we need to run I&#39;m just going to paste this down here we go we have our DB generate command which is going to run drizal kit generate we have a migrate command to run migrate and we have a studio command to run Studio the generate command will generate migration files for us so now that we&#39;ve changed our schema we should probably create those migration files npm run DB generate there we go give that a quick second to run and we should see it&#39;s going to run and if we look over into our DB folder you can see we have this migration folder and in here this is all of the SQL code that needs to run to create our entire database and every time we make changes We&#39;ll add a new file to that Migration by using the generate command now we can use the migrate command to actually push those changes up to our database so now that we have our database URL we&#39;re actually pushing those changes to our database and now if I go to Neon and I look at all the tables for our particular database you can see we have a table for all of the different things that we&#39;ve created inside of our application so now we&#39;ve actually connected our database with the changes that we just made using that migrate command the last thing is the studio command and this just allows us to actually view our application from our Local Host if we really want to if I open this up you can see that now we can view inside of here essentially the same thing we can view inside a neon all of the different rows in our database there&#39;s no information in there right now so we can just close out of that now even before we start working on more information for our dashboard I want to make sure all of our users have a subscription tier as soon as they sign up because because we have this free tier I want to associate someone with a free tier as soon as they sign up for our application and clerk makes this really easy to do if we go back over to clerk we actually have the ability to configure different things inside of our application I&#39;ll make this a little bit larger click on configure and if we scroll down we have this web hook section this web hook section allows us to actually run specific code in our application when certain things happen such as creating a user so let&#39;s add in an endpoint we need to give this a particular URL and then we can associate it with specific events such as user created that&#39;s the only one we really care about you can also make sure when the users are deleted that you do certain things in your application and so on but for ours we&#39;re just going to deal with user created for now actually let&#39;s go ahead and do user deleted while we&#39;re at it might as well now to make sure we understand how everything in here works we can go up to this view doc section that&#39;s going to open up the documentation for this and if we scroll all the way down it&#39;s actually going to tell you exactly what each of these web hooks looks like and it&#39;s going to tell you how everything works and most importantly it&#39;s going to give you the code to actually implement this inside of your own application so this section for sync data to your database if we click here this is going to give us a step-by-step guide on exactly what we need to do first we need to actually expose our application to the Internet so that we can hook up to it with clerk they tell you to use endro but if you&#39;re using vs code the ability to port forward is built into vs code click on ports and click forward a port and just type in your port for ours it&#39;s going to be Port 3000 this is going to set up a forwarded address and we need to make sure we set the visibility to public so that way clerk can access this information then all we need to do is just copy that address and inside of clerk where we need to set up the endpoint you URL copy in that address this is how they&#39;re going to connect to our application then what we need to do inside of clerk if we come back over to here is this going to tell us exactly what to create so first create the endpoint in our clerk dashboard that&#39;s what we&#39;re going through right now so inside of here let&#39;s go ahead and just click create since we have our events that we want to listen for and that&#39;s going to give us a bunch of information most importantly our signing secret so let&#39;s go ahead and we&#39;re going to copy that over this is our web hook secret for clerk so in our environment variables we need to make sure that we add that information in so we&#39;ll call this clerk web hook Secret there we go I&#39;m going to copy that over into our example as well and then also since we&#39;re using this as an environment variable that needs to be inside of here as well that is our clerk web hook secret which is a z. string there we go that&#39;s all we need to do to get our environment variable hooked up back to our documentation on what to do next we need to add that signing secret we already did that so that&#39;s already done and then finally we can set up a web hook route inside of our middleware so make sure that that is public we&#39;ve already done that inside of our middleware because if we go to our middleware file and we open this up you can see our API is currently public and that&#39;s where our web Hook is going to lay so we already know that that is public finally we need to install this SV Library this is how they actually do the communication to verify everything is coming from Clerk and then finally we just need to create the endpoint for it and put this exact code inside there so I&#39;m going to copy this code over and I&#39;m going to create an endpoint inside of that API route so inside of here create an API folder and inside of that API folder I&#39;m going to put a folder specifically for handling all of my web Hooks and I&#39;m going to create a folder specifically for clerk so in here route. TS and we can paste in all of the code that it gives us this is what we need to run and it literally is essentially as simple as that now I&#39;m going to clean up this code slightly so the very first thing I&#39;m going to do is I&#39;m going to take all this stuff for getting all of our different headers I&#39;m going to paste in my own code version of that so you can see we&#39;re getting our headers and we&#39;re getting the information specifically related to svix and we can check if any of this information is not there we&#39;re going to return an error down to the user so at least we know that we have all the information that we need the next thing I need to do is to be able to get the information for the payload this is like all the Json information for our new user being passed up to us and then we can get our web hook secret which is our EnV dot make sure I import EnV from the server version there we go and this is going to be our clerk web hook secret so we&#39;re going to be passing that directly into here and that&#39;s going to give us back an event I&#39;m going to rename this to event just to make it a little easier to work with there we go it&#39;s a little more descriptive that way so we&#39;ve created our web hook we&#39;ve created our event now what we&#39;re doing is we&#39;re verifying that all of our information is correct and I&#39;ve rened these variables to be a little bit more you know JavaScript focused by making them camel case like that so now we have verified based on our headers we&#39;re verifying okay does this body correctly signatured by this svx Library it&#39;s just making sure that other people don&#39;t post information to this and it guarantees all this information is coming directly from clerk so then the next thing we need to do is way down here we can set up a simple switch statement so we&#39;re going to say switch on event. type and now we can say you know what in the case that we have a user created I want to run some specific specific set of code so inside of here this is going to be user created and I can access that event by saying event. dat. I get all the information from my new user such as the ID of the user which is really all I care about so now let&#39;s go ahead and write the code to create this user subscription so we can access our database by saying DB Dot and we can do an insert statement on our user subscription table what I want to do is I want to insert the values so for my data inside of here you can see we have our clerk user ID and our tier that are the only required things so our clerk user ID is our event. data. ID then what we can do is we can pass in the tier and by default we want to sign them up for the free tier so that&#39;s all we need to do to actually give the values that we&#39;re inserting into our database we obviously want to await this to make sure that it runs but that&#39;s literally all we need to do to add a user to our database once that&#39;s done we can just add in a break statement here make sure occurred is spelled correctly and that&#39;s it so pretty much all this code is directly from the clerk documentation and that is actually going to run every time we create a brand new user now I&#39;ve already created my user so what I&#39;m going to do is I&#39;m going to delete my user so we can go over to our dashboard real quick click on my user here click on manage account and I want to just delete this account so we&#39;ll say delete account there we go now we&#39;re back onto this page and I can do a quick login and sign up for a user so we&#39;ll click sign up I want to sign up with GitHub give that a quick second and you can see that now we&#39;ve actually signed in with GitHub and it should have called out to our API to actually connect and create a brand new user Force as you can see it&#39;s already made get request to all that made a get request to here but I don&#39;t think it actually made our post post request what we can do is we can go over to our dashboard to check to see if this is working in our endpoint so in our overview for our endpoint we can click on our endpoint itself click on this one and you can see no messages were received or sent but you can see right here actually there was two succeeded messages for user created and user deleted so it was actually properly sending information over so let&#39;s check our neon console to see if we have a user subscription and it looks like we don&#39;t have a user subscription being created so let&#39;s make sure that everything is working as we expected to we can minimize this down a little bit we can put a console log inside of here that just says hi so we know that we&#39;re hitting this particular endpoint and what we can do is we can actually call this replay function which is just going to resend this message for us so we&#39;ll come in here click resend and that is going to resend this and you can see it did make a post request but it went to post slash that&#39;s because I didn&#39;t actually add in my apiweb hooks SL clerk there we go so I&#39;m making sure I call the correct endpoint now let&#39;s try retrying that again we should hopefully see if we do that retry properly it should actually log out high you can see it&#39;s compiling that page and it looks like we&#39;re getting high being logged out we are getting some warnings but we can pretty much ignore but we should see in our database if we refresh that we now have a row inside of our table and we do and if we scroll over you can see that they should be set to the free tier which they are so this is working really really well so now every time a user is created we actually have them being hooked up to a particular tier so now I should be able to have that free tier on this user account and I can do different verification now before we dive into that I want to do a huge thing that&#39;s going to massively clean up our code it&#39;s really easy when you&#39;re working with a database to just write a bunch of DB statements all over your application and then all of a sudden you realize that your database code is literally everywhere scattered throughout all of your application it&#39;s difficult to track what&#39;s going on to fix errors and so on so what I want to do is I want to create a brand new section in our application for only storing database related queries so I&#39;m going to put a server folder for all of our server related code and inside of here I&#39;m going to create a database folder now in this database folder I&#39;m going to create a bunch of different files for all the database interactions we can do for example anytime I want to deal with a subscription it&#39;s going to be in this subscription. TS file and now I can create a function that&#39;s going to create a user subscription so I can export a function called create user subscription just like that and it&#39;s going to take in whatever data is related to creating this so to easily get that we can just say type of that&#39;s going to be coming from our user subscription table Dot and we can just use the infer insert that&#39;s going to essentially say that this data is whatever we can insert into our particular table then we can just do our database call so I&#39;m going to come back to here I&#39;m going to take this entire database call copy that out of here I&#39;m going to paste that directly into here and we&#39;re just going to return that for now we&#39;ll say DB just like that and this is going to be taken in all of our data so we&#39;re just going to pass in our data as our values so now this is where we do our create we can come back into here and what I want to do is I want to call that create function just like this pass it in this information and now my database information is being stored in this one file so every time I want to deal with a subscription in my database I can write the code in this file and I can reuse it everywhere in my application and I can even make sure I get rid of all these different Imports I don&#39;t need and you should see if you do this that the database file is never imported anywhere except for inside this DB folder that makes your code much easier to clean and if you ever want to change from drizzle to prismo or something else you can just change these one set of files and that&#39;s going to do all the changes for you throughout your entire application this is a must-have on any larger scale application you may not think this is as important it is but I guarantee you once we start dealing with caching and other more complicated database queries you&#39;re going to see how amazing this is now one thing I want to do is on this if there&#39;s a conflict I want to do nothing so if for example I try to insert a user into the table that already exists I&#39;m going to make sure that we don&#39;t do anything so anytime that the clerk user ID already exist on my table I&#39;m just going to do nothing at all this is really important to have in cases where like I replay this again so if I come back into my clerk dashboard and I were to like replay this user created event a second time and I already had information in my database it doesn&#39;t reset that information or throw error it just says okay you know what they already have a subscription just completely ignore that now in order to handle deleting as well since I mentioned that we&#39;re going to do that let&#39;s go back into our route for that web hook and I want to be able to have another check here so we&#39;ll put in a case this one&#39;s going to be user. deleted and inside of here I just want to do a bunch of deleting so we&#39;re just going to call a function called delete user just like that and we&#39;ll pass it in my event. dat dot this is going to be the deleted users ID which should just be ID now it does say that this ID field could be undefined so we&#39;ll just say if the event. data. ID is equal to null well then we just want to essentially ignore everything so we&#39;ll just come in here and if it&#39;s not equal to null then we want to do this delete user function and this again is going to be coming from that DB folder so inside of here let&#39;s create one for users. TS and I&#39;m going to export a function called delete user which takes in a user ID so we&#39;re going to say clerk user ID which is a string and now we just need to delete everything from our database that&#39;s associated with that user so we can come in here and we can say DB and we want to do a delete statement and we want to delete from our user subscription table so we&#39;re going to say user subscription table where and we want to do it where the particular ID is so we can say where equals clerk whoops user subscription table. clerk user ID is equal to our clerk user ID so first of all we&#39;re going to do this delete function and I want to do all these inside of a batch so say DB batch and what that&#39;s going to do is it&#39;s going to make sure it runs all of these one after the other and if any of them fail it&#39;s going to roll back the entire thing so first of all we&#39;re going to do this delete make sure I put this inside of an array there we go so we&#39;re going to do our delete for our users in the subscription section then after that we&#39;re going to do a delete and this time we want to do it for our product table so we&#39;ll say product table where and we want to do the exact same wear Clause I&#39;m just going to copy that over and I&#39;m want to make sure that this is for our product table and let me make sure I capitalize that there we go product table and that&#39;s all we need to do because our clerk user is only associated with products and it&#39;s only associated with a user subscription and the really nice thing about doing it this way with all of our on delete Cascades that we set up is in our database if we look back at that file in our schema we set up a bunch of on delete Cascade so if I just scroll up a little wage you&#39;ll see that whenever we delete for example a product it&#39;s going to delete all the country group discounts associated with them and so on so anytime we delete something it&#39;s going to make sure it does that cascading for us so to be able to delete a user all we need to do is do this and we can just return this so we can make sure we can await it back into here so delete user there we go so now when we delete a user it gets rid of all their information from our database and we can really easily test this by just coming into here and I&#39;m going to delete this particular user account so come over to Security delete account whoops make sure I spelled that properly click enter you can see it didn&#39;t look like any errors were thrown if I go over to our neon database we should see that there&#39;s no longer any subscriptions when I refresh the page give that a quick step and you can see our subscription has been removed so it properly deleted everything and now if I were to log in and sign up with my account it&#39;ll recreate that subscription for us so we have deleting and creating users hooked up properly now when we start dealing with stripe we&#39;re going to need to come in here with like a to-do that says remove stripe subscription so if they are on a stripe subscription we&#39;ll want to make sure that we cancel that but otherwise we should be good to go now up until this point we&#39;ve done a lot of work for our application to essentially be a blank page but this has been a lot of groundwork which is going to make moving forward with the rest of our application so much easier so inside of our dashboard we can work on this main page right here so the very first thing I want to do is I want to render out a few of the products that I have so as a user I want to get a specific number of products so I can say const products is equal to and I can say await get products which is a function we&#39;re going to create in that database folder so we&#39;ll say get products based on a user ID so export this as an async function now to get my user ID I can just say const user ID is equal to a waiting off just like that this comes directly from Clerk and gives us essentially the user ID and we actually don&#39;t need to await that because this isn&#39;t asynchronous it just gets it directly from essentially a local storage JWT so it&#39;s really quick and super easy we get the user ID and technically this user ID comes back as string or null we know that we&#39;re on a private page so we know that this is going to be non- null so what we could do is we could put an exclamation point here that tells typescript that this can&#39;t be null but I prefer to do is just to do a check at the top of our page if the user is equal to null then we can just redirect them to the signin page which is something that comes directly from here so redirect to signin we can just call that function right here the reason that I like to do this instead of forcing typescript to say that it could be not null is just because it&#39;s going to make sure that my user ID is now set to not null everywhere in this file so I don&#39;t have to manually type it everywhere and it&#39;s going to make sure that if I accidentally access this off on a non-private page that it&#39;s going to make sure it fails safely for the user that is required so here we&#39;re getting our products so let&#39;s create this get products function so we&#39;re going to go back into that DB folder create a new file called products. TS and we want to export a function called git products now this is a relatively simple function it takes in our clerk user ID which is a string and then all we need to do is just return Calling whoops return Calling DB do query and this query is really nice because we can query on the product table and we can find many so it gives us that really nice syntax that you&#39;re used to with Prisma and that&#39;s because we set up all of our relations in drizzle so we can say we got to do a where and we want to do it where our clerk user ID column which we&#39;ll just call clerk user ID call and we want to check for equality this is actually going to be a function so let me make sure I wrap that in parameters here and what I can do is just call that equal function pass it in my clerk user ID column and my clerk user ID and boom that works now I&#39;m going to clean this up a little by calling this user ID that way I don&#39;t need to rename this file or this column and we can just say user ID just like that so now all I&#39;m doing is just saying hey give me all the products where the user ID matches this user ID and I also want to order them so I&#39;m going to say order by and in this case we&#39;re going to have our properties inside of there this is a function I want to get the clerk user ID and I want to order them in descending order so I&#39;m going to say descending order and this should be actually created at there we go so I&#39;m going to order them by that created at field perfect now for our particular page I want to limit how many things I get back so right now if I import this everything will work but I want to limit this to like six so I want to say limit of six and in my get products I can make sure I take in a limit so we&#39;re going to say we&#39;re going to take in a limit and this is a limit that is optional and it&#39;s going to be a number so now I can just pass that along here because this query takes a limit so like I could pass along a limit of 10 or can just use the limit we pass in so now it&#39;s going to give us only six or it&#39;ll give us all of them if we don&#39;t pass along any limit so now you can see we have our products and we can print out any information we want about our products so the very first thing I want to do is to make sure we have products so I can say here if our products. length is equal to zero then I want to return a component I&#39;m going to call no products because if we have no products I obviously can&#39;t render out the rest of our page so this no products component is something that I&#39;m going to create it&#39;s going to be something only I use on these private pages so we&#39;ll say no product . TSX now this component is going to be a rather simple component we&#39;ll take a look at the code real quick you can see here I just have a ton of margin on the top and I&#39;m centering all my text then I have an H1 that&#39;s rather large that just says you have no products and then finally I have a section that says hey get started by creating your first product and a link that Lings us to the actual add product page so if I give that a quick save give this a refresh make sure that I import this no products component we should hopefully see on our main page that it says you have no products get started by creating a product and this will bring us to the product/ new page which we have not created yet now we should probably go ahead and create a page for creating brand new products so what we can do is we come over to here we can say inside of our dashboard we&#39;re going to create a products folder and inside of here we&#39;re going to create a new folder and we&#39;ll create a page. txx directly inside of there so export a function new product page there we go and to emulate essentially as close as we can what this parody deal site looks like we can come into here and log in and once I log in and navigate to a page you can see that this is essentially what the create page looks like I&#39;ll even click create we want to create one of these and you can see it has this back button a title and then a card with all the different information we want to associate with this thing so I want to create this like back button style card that we&#39;re going to put on our page and that&#39;s going to be a component we can use lots of different places so I&#39;m going to put it in this components folder we&#39;ll say page with back button make sure I capitalize button. TSX and we&#39;ll make sure we export a function page with back button now for this particular page we&#39;re going to have a few different props that we pass in the props we&#39;re going to be passing in is the hre for our back button we&#39;re going to be passing in the title for our page that&#39;s that section that goes up here and then finally all the children which is everything else we render on our page now to give it this really distinct two column layout we&#39;re going to be using grid for that so we can come in here with a div class name of grid we&#39;re going to say the grid columns are going to be Auto and 1fr that way the left column is as small as possible while our right column is as large as possible then we&#39;re going to say a gap in the X direction is going to be four and our Gap in the y direction is going to be eight to space out our top and bottom from our left and right a little bit more then we&#39;re going to come in here and style what the actual icon is going to look like on the left side this is going to be simply a button that we&#39;re going to render out as child and that&#39;s because it&#39;s going to have a link directly inside of it and that link is going to go to our back button href and inside of here it&#39;s going to have essentially two different things first of all it&#39;s going to have the text back which we&#39;re going to give a screen reader only so that way anyone on screen reader knows that this is our back button otherwise it&#39;s going to have a carrot left icon which will give a class name of size 8 to give it a nice and large back button Arrow make sure I close that off and make sure I import button just like that give that a quick little save and before we do anything else we can test to see if this is working like we expected to so we&#39;re going to go into our new product page here I want to return our page with back button just like that close that off we&#39;re going to say this is our inner content and our back button hre is just going to go to our products page there we go that&#39;s going to be dashboard SL products so now we don&#39;t have all the components passed along that&#39;s fine we can click add product and we can see if this brings us to the right page looks like we need to make sure we export this as a default function I always forget to do that there we go now you can see it looks like nothing&#39;s quite rendering right now let&#39;s go back to this page with back button and make sure we&#39;re rendering out our children as well and to make sure obviously that we&#39;re returning this content so let&#39;s give that a quick return you can see we have our back button showing up let&#39;s give it a bunch of styles to make it look a little bit better so first of all we can change the size on this to Icon that&#39;s going to make it more of a square shape so as you can see we now get that square shaped icon I want this to be rounded though so I&#39;m going to say rounded full that&#39;s going to give it rounded style and I want this to have a variant which is going to be outline just like that now by default this outline variant gives us our accent color when we hover it I don&#39;t really like that so we&#39;re going to modify what that outline variant looks like so here on our outline when we hover instead of giving it this accent I&#39;m going to give it the muted color and same thing here this is going to be our muted color so now when I hover you can see it gives me that gray color instead of giving me that blue color which I think looks a little bit better in this particular scenario now we can come back to here and finish off what the rest of this page is going to look like CU now we have our button section the next thing to work on is our title which is going to be inside of an H1 that&#39;s our page title and then finally the next thing that we&#39;re going to have is going to be our children so that&#39;s going to be in our div that&#39;s going to say children just like that now if we give that a save and we make sure that we pass along a page title so we&#39;ll say page title equals new product doesn&#39;t really matter you can see we have new product and we have our text but this text is in the wrong position and this title does not look super great so let&#39;s clean that up go back to our page with back button first of all we&#39;ll work on our title we&#39;ll make the text much larger 2 XL we&#39;ll probably do we&#39;ll make it a semi bold font and we&#39;ll make it so that it&#39;s in the center of the page there we go and this is actually centering it vertically so if we remove that you can see it&#39;s up a little bit and when we add that it&#39;s centered perfectly with this button now for our children to make them in the right section we can say our column is going to start in the second row and that&#39;s going to make sure it starts over on this right hand side instead of on the left hand side and that&#39;s all we need to do to get this entire page with a back button working and when I click back it brings me back to my products page which we don&#39;t actually have yet so that&#39;s why it&#39;s giving me a 404 but we at least know that that is working like we want it to so let&#39;s go ahead in here we&#39;ll change this to create product and now we can work on this intersection which I&#39;m just going to be using a card for so we&#39;ll import card we&#39;re going to have a card header and inside there we&#39;re going to have a card title and inside that title we&#39;re just going to say product details and I want to make sure I change the class on this to be a text of large because I want it to be really large actually let&#39;s make it extra large there we go we have our product details finally after our header we&#39;re going to do our content card content and this is going to be our product details form which is a form we&#39;re going to create for all the different details so over here you know be like things like name description URL so on so for our form this is going to be something that we&#39;re going to put inside this components folder and I&#39;m actually going to create a separate folder specifically for dealing with forms and inside of here I&#39;ll create a file we&#39;ll call product details form. TSX now to work with this we&#39;ll just export a function product details form make sure I actually spell all this properly there we go return n for now we need to import a bunch of components from Shad CN to get this to work so let&#39;s come into here we&#39;re going to go down import a bunch of components we&#39;re going to say npx Shad CN at latest we want to add and we want to add the form component the input component the text area component and we also want to deal with toast so we&#39;re going to add in the toast component as well give that click enter right there and that should import all the components we need but it looks like I spelled text area wrong so let me just make sure I get that spelled properly and now let&#39;s try that again it should import all of our different components give it a quick second it&#39;s asking us if we want to overwrite button obviously we do not so we will not overwrite that and now we have all the different components imported that we need to be able to work on creating this particular form now creating a Shad CN form is really not too complicated once you know how all the different parts work first we need to get our form and this is coming from the use form hook and this is a hook that&#39;s part of a react hook form so we can import use form from react hook form just like that and this use form Hook is going to take a type for what type of thing we&#39;re importing so this is actually coming from Zod since we&#39;re going to be using Zod for actual schema definitions so we&#39;ll a z. infer type of and we want to specify what my schema is this is my product details schema and this is something that we need to Define so I&#39;m going to come up here and we&#39;ll say const product details schema equals and we can say like Z doob and let&#39;s just say it&#39;s an object that has a name which is a string there we go that&#39;s all this is going to do so what we have right here is we&#39;re importing that particular thing as our type and now to make sure that we hook everything up to make sure it does type check checking we can say resolver and we&#39;re going to make sure we&#39;re using the Zod resolver function this is a function that we can import whoops import Zod resolver from and that comes from at hook form resolvers just like that now we have our Zod resolver and we need to make sure we get it from the SL Zod portion of that now we can pass in our schema which is our product details schema and then finally we can specify any default values that we have in our case we don&#39;t have any default values so we&#39;ll just put in an empty object for example we just don&#39;t have any defaults at all since we have no defaults let&#39;s just leave that off for now so now we have our form created and we&#39;re using that Zod schema and right now the only thing in that schema is our name so once we have a form created the next step is to work on actually creating the jsx for our form so we can use the form component from react hook form close off that form component and inside the form component we need to put our very own form and we need to also make sure we pass along all the information from our react hook form form so here we can say form just like that and what that&#39;s doing is it&#39;s taking this form and hooking it up to all the schema related information I have up here and using that for our actual normal form and inside the form we need to make sure we hook up our onsubmit and this is going to be calling form. handlesubmit and we can pass in our own on submit function so this function called on submit this function right here is going to take in all of my values and the values is just going to be the type of whatever our schema is expecting so this values right now is just a name that is a string so we can come in here and now we can do whatever we want with these particular values for now I&#39;m just going to log them out to the screen now we can also do some styling on our form this is purely just visual I&#39;m just going to make it a flex with a gap of six and flex column just to make our form have some spacing between things and then we can specify that we want to create a form field now this is coming directly from Shad CN so we can say form field want to make sure that I import this so let&#39;s just close that off let&#39;s try to do an import looks like it&#39;s not Auto importing so I&#39;ll just manually import form field from and that&#39;s going to be at slui actually components uiform and it looks like it did not import our form components they are there actually they&#39;re in our source components UI folder let me see exactly why they&#39;re not working so if we come over to here they are right in there I may just need to refresh some things on my page actually it looks like maybe that is now working we just need to pass along all of our Fields so for the form field we need to pass along a few things first of all our control this is what Hooks up our form to the actual form field so our form control goes into our form field the next step is the name and this name property is types save our only thing we have is name so we&#39;re going to set our name to name obviously this can be whatever you want for example if I had description in here which is a z. string as well description there we go I could change this to be description or name so we&#39;re just going to do it as name for now and then the final thing that we need to pass along here is our our render prop and this is just telling us what we want to render in this form field so this is going to be a function that takes along all of our Field properties and it&#39;s going to give us something we want to render so with shad CN it&#39;s really easy to do because we have a form item that we can pass in this form item will give a class name of flex grow just because I&#39;m going to put it in a container in a second here I might as well just do that now so we&#39;ll say we have a div with a class name of grid and a gap of six and grid calls of one and large grid calls of two there we go so this is just going to allow me to put two form inputs side by side so I actually don&#39;t even need the flex SC on this because it&#39;s inside of a grid container so inside the form item we then specify a form label there we go and inside the label you can put whatever you want for example it&#39;s going to be the name of our product we&#39;ll specifically call it product name just like that then after our form label we&#39;re going to have a form control and this is where you put your input so in our case we can just put an input field like our text input so let&#39;s make sure I spell input correctly just like that and I want to make sure I close that off and I want to pass along all of my field related information and again make sure I import input correctly looks like I need to manually import that again import input from and that is going to be at components slui input there we go now we scroll all the way down here we looks like all of our errors are cleaned up finally we can add in a form message and this is going to show my error message if for some reason there is a particular error with our form so let&#39;s go over here make sure we import this so we can actually see our form showing up on our page come over here obviously we&#39;re getting quite a few errors right now so we need to go ahead and clean that up so let&#39;s scroll up it&#39;s something to do with this use form function it&#39;s saying it&#39;s not a function I believe part of the problem could be because I imported my form from the wrong section this form should be imported here from react or from Shad CN let&#39;s see if that actually cleans that up give a quick refresh still not quite working oh it&#39;s because obviously I need to be able to use a client component if I want to use client side code so this is a client side component and now we have our product name and I can type inside of there also to prove to you that validation is working I can specify that this has a minimum value of one and it&#39;ll show me the error required if I don&#39;t and now if I just make sure that I do everything correctly by putting a comma in there and I come in here and try to submit my form I get the error required but as soon as I type this in it goes away so this is really nice for giving me errors from my different validations it&#39;s all hooked up automatically and I don&#39;t need to do anything else on my own so I can just copy this down paste it in and all you need to do is change this name property change the label and everything else should just line up perfectly so for me I&#39;m going to change this to my URL so it come into here URL whoops that&#39;s not where I wanted to type that out at there we go URL and this is going to be enter your website URL as the label and the really nice thing is I can add additional field descriptions if I want so I can say form description just like that and add additional information for example for this one I want to make sure that I explain exactly how this works by saying hey make sure you include the https and the full path to your sales page so that this will work now I&#39;m getting an error because I don&#39;t have a URL filled up here so I&#39;ll say URL is a string it&#39;s also a URL string and it has a minimum of one because it is required and this I will Mark as optional because it is not required so now if I scroll down you can see that I get these two side by side well actually they&#39;re top and bottom but as soon as my screen&#39;s larger they should show up side by side as you can see there they&#39;re now side by side and now they&#39;re top and bottom from another depending on what my screen size is now the next one I want to work on is my text area so I&#39;m just going to copy down this entire form field make sure we get our screen a little bit easier to work with there we go minimize this div down and right below it is going to be my description so this is going to be a description this right here is going to say product description and then finally I&#39;ll add in a little bit of description to tell people what this description does there we go make sure I close this off so looks like I need to do that down there close that off there that off there there we go so now I have that optional description and instead of an input here I want this to be a text area which again I need to import manually because it&#39;s not Auto importing so get our text area from at/ components slui text area there we go make sure I spell area properly scroll down and now we have our text area showing up and I&#39;m just going to add a few classes to it so we&#39;ll say min height of 20 and I&#39;m going to say resize none so it&#39;s impossible to resize and now I have my description showing up finally I can add in a section here which is a class name of self end and this is just going to be where I put my button so button just like that make sure I import button I&#39;m going to say that it&#39;s going to be disabled whenever my form is submitted so form. form state. is submitting whoops is submitting there we go and the is submit and here I&#39;ll just sit save so now at the bottom of my form I have a save button and when I click on that it&#39;s going to try to save my form and you can see I automatically get the errors because these things are technically required now before I go about fixing all my validation errors and making it so we can save things I do want to mention one particular thing to you if I inspect my page I&#39;ll just do a refresh here and I go ahead and I start typing information into this product name you notice I get a huge error and that&#39;s because this is going from a essentially controlled to uncontrolled then back and forth from the component so essentially what I need to do is I need to make sure I give it a default value of a string so here my default values I need to have an object where the name is a string the URL is a string and my description is a string that way when I go ahead and I start changing my inputs I won&#39;t get that error you can see now by inspect go back to my console close out of all the errors I type in here you notice I get no more errors showing up on my page so now we go ahead and actually make this onsubmit work and to do that we&#39;re going to be using an action so what I can do is I can open up my folder here inside of my server folder I want to create a brand new folder called actions and inside this actions folder I&#39;m going to create a file called products and actions are just ways to actually call code from the client on the server safely and securely so I&#39;m going to say use server to say that this is actions inside of here export an async function called create product and this create product function is going to take in some unsafe data that&#39;s because you can never trust anything that comes in from the client and this unsafe data is going to be typ based on that schema that I used on my client so I need to take that schema that&#39;s on my client and move it out into somewhere more accessible so I&#39;ll create a new folder called schemas let me rename that to schemas there we go and I&#39;m going to create a new file called products. TSS directly inside there so now I can go ahead down onto my client which is in the app section right here I have that schema defined up here I&#39;m just going to remove that I&#39;m going to paste that directly into that brand new file that I just created I&#39;m going to export that and make sure I import is OD now the final thing I&#39;m going to do is I&#39;m going to make sure that my URL does not have any trailing slashes on it because for example if I type in product slne slash at the very end and hit enter it brings me to the same page as if I didn&#39;t put that slash at the end of my URL so I&#39;m going to do a transform here a transform is a function that gets called to transform your data after it&#39;s been validated I&#39;m going to call a function called remove trailing slash just like that I&#39;m going to create this function as like a utility function so if I go into my lib utils folder I can export a function called remove trailing slash it&#39;s going to take in a path which is a string and all it&#39;s going to do is I&#39;m going to run a simple regular expression to remove the trailing slash so this regular expression says you see a slash symbol at the very end if there&#39;s a slash symbol at the end of it replace it with essentially an empty string super straightforward and simple so now if I go back into my schema and I import this function you can now see that essentially anytime that I call this function it&#39;s going to remove the trailing Slash from my URL so that way there&#39;s no confusion between a URL with or without that trailing slash that&#39;s going to make tracking My Views and so on so much easier so here&#39;s my create product function I need to get my z. infer from the type of and I want to get it from that product details schema so I call it product details schema just like that and now I have my unsafe data directly inside of here properly typed I just need to make sure I validate it also here I need to make sure I import that schema now that I moved it out of this particular file there we go that has been imported properly and let&#39;s go ahead and write my action so the very first thing I need to do in this action is to get my user ID for who&#39;s actually creating this so user ID is equal to awaiting calling that off function and again I don&#39;t need to await that I could just call the off function because it&#39;s going to happen in line then what I can do is I can get a success flag and a data flag and I can get that from calling product detail schema. safe parse and passing in my unsaved data this is just going to go through and validate that all the data that I&#39;m getting in here matches everything inside of this schema if it doesn&#39;t then my success is false so we can go ahead and check that if we do not have any success or if our user ID for some reason is null which should not be possible but if it is then we&#39;re going to go ahead here and we&#39;re going to return down an error to the user so we&#39;ll say error true and we&#39;ll give him a message that just says there was an error creating your product super straightforward so that they know something went wrong because if we get to this point there should be no errors unless someone maliciously passed up some incorrect code or tried to access his page P without a user ID or so on then what we can do is we can create our product and we want to create that product inside of our database so we&#39;ll create a function called create product DB and that&#39;s going to be coming from that DB folder that we worked on so inside of here we have our git products now it&#39;s create a function called create product just like that so this is going to be a rather straightforward function again it&#39;s going to take in my data which is my type of product table. infer select or not infer select sorry infer insert there we go then we can call DB Dot and I want to call insert on my product table I want to insert specific values and that&#39;s just my data that I&#39;m getting passed in super straightforward and easy to do and we can await the creation of that and I want to get the ID specifically from here so I going to say my new product is equal to this I want to make sure this is a sync so I can use a weight inside of it and I can pass along this returning flag and I can say I want to return an ID which is my product table. ID so now when I insert this data into the database it&#39;s going to return to me an array of all the new things inserted which in my case I insert one thing so there&#39;s one value in my array which is going to be my brand new product with an ID of a string so what I can do after that is I can do just a really simple try catch so I can come in here and I can create a brand new product customization so in my product customization table what I want to do is I want to insert some values and the only value I want to insert is the product ID which is equal to my new product ID there we go so I&#39;m inserting a brand new thing inside of here and if for some reason I already have one just completely skip it so if there&#39;s a conflict do absolutely nothing and I want to specify what the target is going to be the target for this one is going to be product customization product ID there we go so if the product ID is conflict just completely ignore it and don&#39;t do anything then we can add in a catch because if for some reason there is an error trying to execute this particular thing well I want to delete my product because when I create a product I want to create both a product and a customization at the exact same time and if I have an error creating my customization I want to delete the product because that means there was a problem and I don&#39;t want to have one without the other so I can come in here db. delete and I want to delete my product table just like that where my product ID is equal to so product table. ID is equal to my new product. ID there we go so that&#39;s going to make sure that when I create a product it also hooks up a brand new customization for that otherwise if there&#39;s a problem it just returns and deletes that now the very last thing I want to do is return my new product back to the user that way where I&#39;m using this inside of my actions so if I go back to my actions I can create that product from the DB so we&#39;ll say import create product and we&#39;re going to be importing that as create product DB from and that&#39;s coming from that DB folder so we&#39;re going to go into our server into our database folder inside the products folder so now I can call this and pass along all the information I want and it&#39;s going to return to me an ID for the brand new table that was created and I can do some type of redirecting for example to a correct location so let&#39;s go ahead and get the create working I want to pass along all my data as well as my clerk user ID that&#39;s all the data to create this and then to redirect I&#39;m going to go to the slash dashboard SL products page but I actually want to bring them to the edit page so I&#39;m going to say ID sledit and I specifically want to bring them to the tab for editing the countries and that&#39;s because on this parody deals website if I were to go to one of these and I were to click edit you can see if I actually make it so you can see because it&#39;s not mobile responsive there&#39;s a bunch of different tabs and I want to just bring them to the tab for editing the actual countries associated with that particular table so we can go ahead and we can make sure we redirect them to that specific tab using our ID right here and we need to make sure we await this because this is a promise and that should be all the code we need to do to be able to create a brand new product and again you&#39;ll notice there&#39;s no database code in this file at all everything for our database is inside of the specific folder for database as you can see only this file has anything related to our database code at all so now let&#39;s go into that particular form and make sure we hook everything up we need to call that create product function I want to make sure I call my action right here I want to pass along all of my different values so I can come in here and I can say const data equals await calling that particular thing make sure that this is an asynchronous function and then if our data. message is there then we want to render out that particular message and first of all we want to check to see if there&#39;s an error so if our data has an error and if we have a message data. message then we want to render that message to the user using a toast toast so we can say const toast equals use toast that&#39;s going to be coming from Shad Cen and to make sure our toast actually work properly inside of our overall layout for our entire application all we need to do inside of here somewhere is render out this toaster and that&#39;s just going to be a location for rendering out all of our different toast doesn&#39;t matter where you put it as long as it&#39;s in your application somewhere so now we can come and we can call that toast function just like that we can pass it along the title for what this is going to say so actually I don&#39;t even need to check for error here I&#39;m only going to check for message because I can check for my error here and render out a different title for example I can say either error or success depending on if it was an error or not my description is just going to be my data. message and then finally my variant is going to be either an error variant or not so if my data. error then it&#39;s going to be destructive otherwise we&#39;re going to have default as the variant so now this is going to render out essentially a toast which is either going to be an error toast or success toast depending on if things worked or not now I do want to fix one particular problem with the code it&#39;s a nextjs problem you&#39;ll notice here that I could technically return nothing for example if I redirect the user I don&#39;t actually return any data so I could have this being null but you&#39;ll notice when I look at the actual form and I look at my data type you can see this is not ever null so there&#39;s a problem with the return type so I need to manually give myself a return type on this it&#39;s going to return a promise the promise is going to have an error which is a Boolean and a message which is a string or it&#39;s going to return null from that promise or undefined sorry so it&#39;s going to return undefined just like that so it&#39;s going to return one of these two different things now you can see here data could be undefined so I need to make sure I check that it could be to find before I run the rest of my code so let&#39;s go ahead and see if all this code that we wrote actually works we&#39;re going to come over to this page and we&#39;ll create a brand new product this is going to be test name we&#39;re going to enter a URL we&#39;ll just say Local Host 5500 and we&#39;ll just give it some bogus description if I click save you&#39;ll see that it looks like it&#39;s saving and it redirected me correctly to the edit page so if I go back to my dashboard we should hopefully see that it no longer renders out no products because we now have a product in our database if I go to Neon and I click on my products you can see there&#39;s a brand new product in the database with that test name so everything was hooked up properly which is amazing so now we can go ahead and actually render out a grid of products on our dashboard so let&#39;s go ahead back over to our page for our dashboard and instead of rendering out null we&#39;re going to render out a bunch of information so the very first thing that I want to render out is an H2 that is going to have all the information for our products so it&#39;s going to say like products for example but I want to actually put this inside of a link so we&#39;ll give it a link here real quick our href is going to bring us to the dashboard SL products page and that&#39;s because on this dashboard I&#39;m going to render out things like analytics products and so on so I want to be able to have a link that lets me go between these different things so I can put my products directly inside of there and I&#39;m going to add an arrow right icon just like that close that off and I&#39;m going to give this a class name of transition transform and that&#39;s cuz I&#39;m going to do some fancy animations on that by making it so that anytime I hover over this particular link I&#39;m going to animate it so for the link I&#39;m going to give it a class name of group just like that and here I can say group hover I want to translate this in the X Direction by just a little bit so it&#39;s going to make the arrow move just slightly to the right when I hover and these small little touches are really what bring your application from eh to really impressive to users so now let&#39;s finish off the rest of the classes on our link for example I want to have a flex and a gap of two on my items to be in the center and when I hover over it I want to give it the underline treatment so that they know that this is a particular link now we should go ahead and give that a quick save and we can see we got our products text showing up and when I hover you can see the arrow moves off to the right which is just a really nice little flavor right there now to style my H2 to make it look a little better let&#39;s come in here and make the text quite a bit larger margin on the bottom of six text 3XL we&#39;ll make the font that semi bold font we&#39;ll also use some flex and we&#39;ll justify some space between all of our different elements there we go and that&#39;s because for this product section I&#39;m also going to add a button for creating a brand product right here so we&#39;ll create a button this is going to be an as child button just like that and inside of this button I&#39;m going to have a link with an HF that goes to the new product page so dashboard SL products new just like that new product and let&#39;s even add in a little plus icon into it as well there we go plus icon let&#39;s say the size is four margin on the right of two and close that off give that a quick save make sure I import my button component and now we should hopefully see we have our new product button so now we have the ability to actually go to the products page which we haven&#39;t created yet we have the ability to create a new product directly from the dashboard and we have this nice little hover animation over this products link let&#39;s go ahead and make it so that we can render out all of our products we&#39;re going to do that inside of a products grid component so we&#39;ll say product grid and we&#39;re going to pass in all of our products just like that and the reason I&#39;m making my own component for this is cu I&#39;m probably going to use this exact same grid on my products page and on my dashboard so it just makes things easier for me to work with so we&#39;re going to come in here we have our product grid I&#39;m going to go back over to my component section this is used only on our private pages so we&#39;ll create our product grid just like that in here export function product grid there we go and to be able to get the type for this I&#39;m just going to copy over the type because it&#39;s a little bit easier than making you watch me type it you can see it&#39;s an array of products with name URL description and ID relatively straightforward stuff we are probably already familiar with this because that&#39;s what our product structure looks like now inside of here we can return a div with a class name of grid because we want it to be a grid by default we&#39;re going to have one column for our grid we&#39;re going to move up to two columns when we have a larger screen size so grid calls two and then when we have an even larger screen size we&#39;ll move up to three specific columns and then I want to give a gap of four between all of my columns before I Loop through each one of my products and I render out the product card so for the product make sure I spell that properly I want to render out a product card just like this which takes in a key which is my product. ID and it takes in all the information for my product so now I can create this component which is pretty similar to this component up here so product card just like that it&#39;s going to take in all of my product information which is just this right here so it&#39;s going to be whoops ID name URL description just like that and there we go that should be all the typing I need for that and now in here I can return my card so let&#39;s create a card just like that import that properly we&#39;re going to have our card header and inside of our card header I&#39;m going to have a card title and this is just going to be essentially the link that goes to my particular product to edit it so let&#39;s go into the here card title has a link with an href that goes to that edit page so that&#39;s SL dashboard SL products SL whatever my ID is sledit there we go and that&#39;s where I&#39;m going to put my product name directly inside that link now let&#39;s make sure I get these imported properly so we get rid of all those errors there we go we have our title showing up give that a quick save refresh over here and make sure that I import my product grid properly we should now see we have a card with that test name inside of it so that looks really good and on larger screen sizes you can see we have it showing up inside of a grid specific layout so now let&#39;s go back into that product grid and modify what our product looks like so below my title here I&#39;m going to have a description just like that and this is just going to be whatever the URL of that product is just like that and then below my header I&#39;m going to have card content and this is going to be where I put the description of my card just like that there we go that&#39;s showing up perfectly and I only want to show that if I actually have a description so we&#39;ll save description description then we&#39;ll render out that card content there we go so now if we don&#39;t have a description for this particular product for example if I create a brand new product and I don&#39;t give a description there we go give it a save and make sure we navigate back to our dashboard since this page doesn&#39;t exist yet you&#39;ll see it doesn&#39;t render out that section for the description now I also want to add a button here that allows us to create a drop down menu for things like edit and so on so if I go back to here make this so you can see you can see I have this little button which means like edit and so on so I want to be able to create a button that allows me to do that as well so that is going to require some more Shad scan components so the components that we&#39;re going to need in this case are the dialogue component the alert dialogue component and then finally we need the drop- down component so let&#39;s just click enter on that to install all those components and it looks like I probably spelled something wrong there&#39;s no drop down I believe it&#39;s called drop down menu that should hopefully fix the particular problems I&#39;m running into there we go it looks like it&#39;s installing everything for us and once that&#39;s installed we can start to use those particular components I don&#39;t want to overwrite my button and there we go we now have our different components so first let&#39;s create the particular button that we need to have so we need to go inside of our card header and create a div to be able to space some things out cu I want to put my button on the far right so we&#39;re going to use flex with a gap of two justify between to give me that spacing and items on the end to make sure everything is pushed as far down as possible and this is going to go all the way onto the the other side of my header or my title sorry there we go so right before my description because I want it to be in line with my particular header then what I want to do is after my title I want to be able to render out that button so we&#39;ll say button variant for this one after I make sure I get the button imported is going to be my outline button and the class name for this is a size of eight with a padding of zero and inside that button I want it to be a DOT horizontal icon with a class name of size four and we also should probably put some screen reader text inside of there so this is just going to say div class name screen reader only and this is just going to say like action menu something like that just so that they know that this is something they click on and now we have that button on the right hand side that we can click on now the first thing I want to do is convert this over to a dropdown so to do that we need to put everything inside of the dropdown component there we go we got dropped down and it looks like it&#39;s not letting me import this information correctly so I have to manually add an port for that all the way up here drop down from that&#39;s going to be slash component SL UI dropdown and actually I think it is dropdown menu and I think it&#39;s actually with a hyphen there we go that should import it there we go it does import that drop- down component for us and it looks like it says that there is no component with that name let me make sure I got this right drop down menu is what it&#39;s called so let&#39;s come over here drop down menu and drop- down menu then inside that drop- down menu we need the dropdown menu trigger there we go and this trigger is just going to wrap our button whatever we want to have open our component so we can say as child to render that button out inside of our drop- down menu trigger and now when we click on this it&#39;ll open up a drop- down menu as soon as we create the content so drop down menu content inside this content which I want to give a specific size so we&#39;ll say w of 56 that&#39;s going to be constraining the size of what this menu can look like we&#39;re going to have a drop down menu item as child and we&#39;re just going to render out essentially a link that&#39;s what all these are going to be this one&#39;s going to be a link that allows us to go to editing this particular application so we already have our edit link somewhere else but we&#39;ll just retype it out dasboard SL products sledit actually we need the ID first so ID sledit close off this link and just make it say edit and let&#39;s make sure we import this drop down menu item give that a save and now you can see when we open this up it has that text of edit directly inside there and if we wanted it to be a little smaller we can actually get rid of this class name and I believe that&#39;ll just shrink it down to a little bit smaller size I think that looks a little better so we&#39;ll keep that class name off there now we&#39;ll copy down this drop- down menu item because we need another drop- down menu item and this one is not going to be a link this one&#39;s just going to say add to site we don&#39;t even need the as child cuz that&#39;s all that&#39;s going to do there we go we now have the add to site button as well and I&#39;m going to copy this over one more time and this one is going to be for deleting so we&#39;ll say delete just like that so now over here I have this delete button as well I also want to separate my delete section so I&#39;m going to use a drop- down menu separator all that&#39;s going to do is add a nice little line between this add to site and delete to make them a little bit more distinct from each other so you don&#39;t accidentally click delete if you don&#39;t really want to now to be able to make this add to site work when I click on it I want it to make a popup on my screen that shows me exactly what I want to do and same thing with delete I want to create a popup that says are you sure you want to delete this so to do the popup for the very first thing I need a dialogue so I can say dialogue just like this and wrap my entire menu in this dialogue then I need a dialogue trigger which is going to be this drop- down menu item so we can say dialog trigger just like this and wrap my entire thing in that and that is going to be as child and again this is not letting me Auto Import so I&#39;m going to come all the way up here import dialogue from and that&#39;s at/ component UI dialog there we go now if we scroll down here we can import our dialogue trigger give that a quick save and now when I click on this it at least should render my dialogue as soon as I put some dialogue content inside it here so to do that directly outside my drop down menu content I can come into here and I can create a section for my dialogue content so it&#39;s like dialogue content just like this but I&#39;m going to create a separate component for this which is going to be the add to site product model content I&#39;m going to pass along the ID for the product that I want to actually do this for so this is a component that I need to create so in my component folder let&#39;s go ahead and we&#39;ll create that component. TSX export function with that name and this is actually going to be a client component because I&#39;m going to have the option to actually copy things which requires me to deal with the clipboard which is a client only state now to get started I&#39;m going to paste in just the basic starting board plate code for our dialogue I&#39;m going to import all these things and then explain exactly what&#39;s going on inside of my code here let&#39;s get that one imported there we go get our description imported so really all I&#39;m doing is creating my dialogue content that says start earning PPP sales and a description of exactly what this is going to do so now if I come over to my thing I&#39;m also making it so that it&#39;s a much larger size dialogue as well with some large font so if I click add to site after I make sure that this is properly imported there we go you can now see start ear name PPP sales close that out click add to site and you can see it opens that up with all my information directly inside of there refresh the page you can see boom open that up now all I need to do is add the code to copy and so on so after my dialogue header what I want to do is I want to add a pre- tag directly inside of here is where I&#39;m going to put all of my code for the content so in the pre- tag let&#39;s add some code and if I spell that properly there we go we can add the code that we want to do I&#39;m just going to put this inside of code we&#39;re going to generate that code in a little bit let&#39;s come up to to here I&#39;ll paste in what that code should look like we give that a quick save all this code is doing is saying okay here&#39;s a script tag that points to our current URL SL API products whatever my product ID is and banner so it&#39;s really just a URL that points to an API endpoint and they&#39;re going to put that in their site and it&#39;s going to download some JavaScript for them when they put that on their site so let&#39;s come in here ID string there we go and we want to make sure we add these variables to our environment so this is going to be an environment which is from our client and we need this next public server URL again we have type safety on all this information which is really great so inside of that data folder in our EnV for our client we need to add along the information for our server URL which is z. string. URL and we need to put that down here as well which is going to be process. env. that there we go and then finally in our actual EnV files we can come into here we have our database we have our clerk this is just going to be other for example and this is just HTTP Local Host 3000 and when we deploy our site we&#39;ll obviously change this to something else so now in our example we can paste that down and keep the value in there because that&#39;s pretty much what we want so now if we go back to the file we were just working on let&#39;s open that up that is inside of our dashboard components and we have our add to site modal right here dialogue now our script is showing up and if I give that a quick save we can actually see what this looks like by adding to site you can see we just get this script tag it&#39;s not really styled right now so I&#39;m going to go ahead and add some styles to this so we&#39;ll say class name margin bottom of four overflow in the x is going to be Auto so we get a scroll bar padding is going to be four background is going to be secondary it&#39;s going to be rounded the max width of this is going to be our screen extra large size so it doesn&#39;t get too big we&#39;re going to make this text on it in the foreground for the secondary so that&#39;s just going to put it inside of a box which we can scroll across which looks a lot better and as you can see this is just a link to a script that points back to our API so essentially they&#39;re going to take this code copy it paste it into their own application for example like this and then when their page loads it&#39;s going to call our API and we can load down the banner for them that&#39;s what this code is going to do now I want to create a button that allows them to copy this particular code so I&#39;m going to come in here I&#39;ll copy this over so you don&#39;t have to watch me type it and I&#39;ll explain what&#39;s going on so first of all getting a button just like this super simple button the on click function we&#39;ll get to in just a little bit but inside of this button all we&#39;re doing is we have a get children function right here which is going to get the text inside of here and an icon that we&#39;re going to be rendering out to the user so all this is going to do I&#39;ll copy over these two functions so we can see them get children is just going to be taking in this copy state so whether when the idle State the copied State or the error State it&#39;s going to change my text so I have a copy button that when I click on it is going to say copy code and when I click on it it&#39;s going to say copied if it was successful or it&#39;s going to say error if there&#39;s an error same thing here I&#39;m going to render out a different icon so I&#39;m going to get this icon this icon and this icon from there now I want to be able to define the type for my copy state so we&#39;ll copy that over you can see my copy state is either idle copied or error and to be able to get that state we&#39;re going to be using a use state so copy State set copy state is equal to use state of the copy State type and by default we&#39;re in the idle state so let&#39;s import that from react there we go now we can scroll back down here and we can get our icon so we can just get that by calling a simple function right here getting our icon from our state and that&#39;s going to give us the correct icon we want to render and that&#39;s because we want to render a different icon if there&#39;s an error and so on finally we need to import this dialogue close just like that which is going to be a button for closing out of our dialogue and now when our on click to understand what&#39;s going on here is when they click this button I&#39;m going to write the text to their clipboard so I&#39;m going to copy the text for them set my state to copied if it was successful and after 2 seconds bring it back to the idle State same thing with an error after 2 seconds bring it back to normal so now you can see we have a copy close copy code Button as well as a close button close just close relatively straightforward when I click copy code you can see my text changes and so on and if I come over here and I click paste you can see it paste exactly what was copied in my clipboard so it&#39;s a lot of code to do this but most of the code is just with handling the state if I were to remove all the state code I could get rid of this code and all this code down here but the state is nice to be able to give people a visual feedback that everything was copied successfully and so on and now I have my modal and on different screen sizes you can see my Modo looks different so you can see it&#39;s perfectly responsive to all different screen sizes so now that we have our copy Modo all done and setup the final thing we have left for this grid view is just work on this delete button and make sure that&#39;s working as expected so we can come back to the page we were just on for our grid so there we go our product grid we can scroll down to this section where we have our dropdown and inside of our dropdown menu area between our dialogue and a dropdown we want to have our alert dialogue show up next so we&#39;re going to bring that in make sure we put that between the same two sections and we need to have an alert dialogue trigger just like we did before so here alert dialog log trigger close that off there we go make sure that this isn&#39;t as child so it&#39;s going to render properly and then we need to have the content so the content for this is going to be our delete product alert dialogue content just like that pass along the ID just like we were doing before and I&#39;m actually going to move this add to site product model down into our dialogue just so our tree is a little bit cleaner so we have our alert dialogue with its content drop down menu with its content and our dialog with its content so now let&#39;s go ahead and make sure we import these things it&#39;s looking like I&#39;m going to have to manually import these again so it we&#39;ll just come up here import alert from at SL components SL UI alert there we go and down here let&#39;s go ahead and make sure that these are getting imported as well actually it&#39;s called alert dialogue not alert so let me bring that up there we go and this is alert dialogue there we go that should clean up those Imports and now we just need to manually import these ones and we need to create the file for our alert dialogue content so let&#39;s come over to here create a brand new file. TSX there we go looks like I created it in the wrong place export function paste that in there and we know that this is taken in an ID and the ID is a string now the bulk of this is going to be very straightforward code so I&#39;m just going to paste it down do all of our Imports and explain exactly what&#39;s going on here in just a second so let&#39;s get all of our Imports done get the footer and the cancel in there let&#39;s make sure we close out our footer and close out our dialogue content there we go so what I&#39;m doing here is I&#39;m rendering out the content I&#39;m rendering out a header which just has a title are you sure and the description says hey you cannot undo this this will permanently delete your project or your product that makes sense we want to make sure people know that this is a permanent thing then the next thing I want to do is I want to render out the ability to actually confirm this so that&#39;s our alert dialogue action make sure I import that from the right location there we go this alert dialogue action is essentially just going to render out a button for us so we can set the button to be disabled in a certain State and that&#39;s going to be when our delete is pending and that&#39;s because all the way up here we&#39;re going to have an is delete pending and a start delete transition that&#39;s coming from the used transition hook this allows us to essentially call code from our client onto the server and get a nice loading State also I&#39;m going to render out some error messages using a toast in case there was an error so we&#39;ll say use toast just like that there we go so now we have the ability to do a delete with something showing up we also want to have some text inside of here maybe delete and we also should probably put in an onclick event listener which is where the bulk of all of our code for this entire component is going to go so the very first thing inside of here I want to do is I want to call the start delete transition and while this code is running I&#39;m going to get that nice little loading state so that&#39;s going to be an asynchronous function and inside of here all I want to do is delete my product so we can say data is equal to calling delete product and passing it along the ID that we want to delete so we need to create this as an action so we can come all the way back to where we have our server with our actions and inside of here I can export an async function called delete product just like that this is going to take in an ID which is a string and I can use that inside this function so the first thing I want to do inside of here is get my user id which is equal to calling that off function then if for some reason my user ID is equal to null I&#39;m just going to return an error so we can say error is true and message there was an error deleting your product there we go then if there is no error at all map that inside of there just so it&#39;s a little bit cleaner and easier to work with so now if there is no error we want to delete this but again I don&#39;t want to call my database directly in here I want to call my function to delete things from the database so we&#39;ll say delete product call this from the database just like that I&#39;m going to pass it along my ID and my user ID to make sure I only delete a product if the user is associated with it so now let&#39;s create that function inside of here export async function delete product that&#39;s going to take in an ID which is a string and it&#39;s going to take in a user ID which is a string as well and all I want to do is call await db. delete on my product table and I specifically want to do it where and so I want to do an and query the equality of my product table. ID is equal to my ID and the equality of my product table. clerk user ID is equal to my user ID so I only want to delete the product if they have access to and from here I can actually get some data back from this to get the number of rows that were deleted so I can say row count just like that and then I can say return row count is greater than zero this means that there was a successful delete so it&#39;s going to return true or false if it was successful in deleting so we can say const is success is equal to awaiting calling that function and I need to make sure I import that from up here which is delete database or delete product as delete product product DB there we go and it looks like I didn&#39;t put these inside of an object so there we go there&#39;s my thing but actually I think what I&#39;m going to do is I&#39;m going to go into that function and redefine how I did this as an object because I find that generally objects are a little bit easier to work with when you need to pass things along to make sure you don&#39;t do it incorrectly so that&#39;s a string user ID is a string as well there we go that cleaned that up a little bit all the code is still working the fine as fine as it was before and now we can say if is Success then we can return actually we might as well just do this all in one line we&#39;ll just say return error is equal to is success and we&#39;ll also return a message and we&#39;ll come up here const error message is equal to just so I don&#39;t have to type this entire thing out twice there we go error message paste it into there so if my success then I want to render out one message otherwise I want to render out my error message so we&#39;ll just say successfully deleted your product there we go make sure I close everything off looks like it is all closed off but it looks like up here I have an extra quotation that&#39;s where my error is coming from so now I have this delete product function done now what I need to do is make sure I have everything just hooked up properly so this first of all I should probably import that works fine now what I can do is I can go into here make sure that my delete product is being imported make sure I get the action version properly and now I can say if data. ER actually I need to make sure I wait this first if data. message which it should always have but just in case it doesn&#39;t then I can render out a toast message so up here I already got my toast so I can essentially do the same thing I Ed my toast last time so let&#39;s just search for where I used my toast last time to just copy over that code so here take that code and we&#39;re going to copy it into this section right here cuz the code is essentially exactly the same as what I had before now I&#39;m going to get a toast message properly back and I need to make sure that this is a client component since I&#39;m using client side code so now if I wanted to for example delete this one I can come in here click delete are you sure yep I&#39;m sure I want to delete there&#39;s an error it looked like my error messages and all that was kind of messed up so let&#39;s go back and make sure everything is working properly inside my action you can see here if it&#39;s successful successfully deleted your project otherwise it&#39;s going to show my error message error should be the opposite of is Success so it should have actually deleted my product so if I refresh we can see the product is gone the reason why you didn&#39;t see anything change though is cu I didn&#39;t actually deal with caching and revalidating my page properly now you may think well that&#39;s easy to fix all you need to do is just put a revalidate path in there if I can actually spell properly revalidate path and we know that our path is the dashboard path and boom that would fix our problem but we also render this on the products page so now we need to add in the products path oh and you know what we also have to do with the edit page as well so we need to put that in there and oh maybe it messes with our analytics or something else having to manually put every single path you need to revalidate is incredibly tedious and difficult to do so instead of doing our revalidations with our path here I&#39;m going to be handling this using tags and I&#39;m going to have a full robust system this is honestly the thing that I think is the best about this entire project is how we&#39;re going to be handling caching with tags and it&#39;s going to be really nice because everything&#39;s going to be handled in one place so we&#39;re going to have like a cash manager almost so inside of our live I&#39;m going to create a brand new folder called C.T this is where all of our caching is going to take place and I&#39;m essentially going to have three different tiers of caching the first tier is like a global cache so like for example the countries there&#39;s the same amount of countries for every user and if I change one country I want to refresh my entire cash for all of the countries the next tier is going to be a user tier for example when a user creates a product I don&#39;t want to refresh the cash for all the products I only want to refresh the cash for that user&#39;s products and then finally there&#39;s the instance where I have an individual product for example if I delete this one product I only want to update the cache for that one product I don&#39;t want to update the cache for literally everybody in our entire application so that&#39;s how I want to make sure I handle my caching so I&#39;m going to have a few different functions inside of here I&#39;m going to have a get Global tag function which is going to be how I get a tag for a global cache I&#39;m going to do the exact same thing then for a user tag so this is for user level caching and then I&#39;m going to have a final tag tag here for ID level caching so I have my three levels of caching I have something that&#39;s at the global level the user level and the ID level and to determine what I&#39;m caching it&#39;s going to be based pretty much on my database so I&#39;m going to export a constant called the cach tags and that&#39;s going to be an as const so I make sure that this is never changing and inside of here I&#39;m going to say for example my products is going to be a string called products so now I have the ability to cach anything with this product tag and I have the ability to do it globally with a user or with a particular ID so here all I want to do when I cach something globally is pass along a tag which is a key of the type of cache tags there we go so now this tag is either going to be products or whatever else I pass in here for example if I have the ability to do product views this would have product views and now you can see that I have two options that this can be so to get a global tag I&#39;m just going to return the text Global followed by a colon followed by whatever my tag is so it&#39;s going to be cach tags of my tag and again I want this to be a constant variable so I know that this is going to return to me a string that is always either Global products or Global product views now for my user tag it&#39;s going to be very similar this is going to take in a user ID which is a string and it&#39;s also going to tag in this particular tag just like that so now here I want to pass in my user followed by my user ID followed by hyphen to distinguish that and this is as const so now you can see here it&#39;s always going to be user colon whatever the ID is- products or product views now the final thing I want to do is the same thing for the ID but instead of saying user this is going to say ID and this is going to have an ID here and I&#39;m pretty much going to copy over the exact same types so now we have our ID and again you can see when I overover this it&#39;s ID colon whatever the ID is products or product views so now I have three different granular levels of caching the final thing I want is a function just to clear my entire cache so we&#39;ll say export function clear full cache just like that and that&#39;s going to call revalidate tag and it&#39;s going to call it with this star symbol and this is something I&#39;m going to put as a tag on every single thing that is cached to my application that way if I call this function I can clear the entirety of all of my cache across my entire application this is kind of useful for development or if you do something that really needs to just nuke the entire cache now the next thing I need to do to make sure I handle caching properly is to make sure that I only allow certain tags into my cache so I&#39;m going to export a type called valid tags and this is going to be equal to the return type of my git whoops type of get Global tag just like that or it&#39;s going to be equal to the return type of my user tag so we can come in here with our user tag and the same exact thing for my ID tag so this valid tags is either going to be a global tag a user tag or an ID tag so now I know all the different types of tags I can use and I have the ability to create those tags now all I need to do is actually set up my caching cuz this just gives me the tags that allow me to revalidate and cache things now I need to make sure that I actually do this caching now in nextjs the way that you cache something let&#39;s go back to our database file we&#39;ll just do products for example and we have this git products function the way that you cache things inside of nextjs is you call the Cache function this is built into react and this allows you to Cache something for each individual request and you also have the unstable cache function in nextjs that allows you to cash things across multiple requests this is similar to how fetches are cached by default this allows you to cach things like database calls as well so we need to wrap all of our function calls in a cache and an unstable cache call and the nice thing is we pass in a function here it doesn&#39;t really matter what it is and then you have a second parameter where you can pass along all the different tags that you want to Cache but first of all we need the key Parts which we&#39;re going to put as undefined because that&#39;s just going to default them to whatever they should be and then we&#39;re going to come in here and we can say tags and this is where we put an array of all those different tags so for example I could say like Global and then products and this is going to tag things globally on the products table and so on so this allows me to do all my different tagging so what I want to do is I want to implement this in a helper function that makes it a lot easier and more type safe so let&#39;s get rid of all those Imports we don&#39;t need them anymore go back into our caching section I&#39;m going to create a function which is going to be called DB cach and there we go this is going to take in some props and all I wanted to do is call the cach function from react I also wanted to call unstable cache that&#39;s going to be from nextjs and I want to pass it in whatever my function is now in our particular case I want to essentially just get the type of whatever unstable cache is and pass it along as my props so my props here or my arguments or whatever I want to call them we&#39;ll say args just like this is going to come directly from whatever the type of the unstable cache is so what I can do my first argument is going to be my call back function so that&#39;s parameters and I want to get the type of unstable cachee just like that and I want to get specifically the first property from there so that&#39;s going to give me my call back function so I can pass that in just like that and that&#39;s the first parameter passed along now I know for a fact I&#39;m always going to pass along undefined as the key Parts the key Parts essentially determine how do we know what the ID of this cache is like if you have different parameters you pass along to a function it&#39;s automatically going to generate the key Parts based on the function name and the parameters you pass along so as long as you make sure that everything you pass along to your function and the name of the function is unique that&#39;s all you need to do for the key parts so leaving it undefined will work by default but if you need to add extra things to uniquely identify that function you can add them in here but for our case everything works with undefined now finally we have where we&#39;re going to get all of our different tags that we need to be implementing into this particular section so we can say tags like this and that&#39;s going to be our second parameter that we&#39;re going to pass to this particular function it&#39;s going to be an object with all of our different tags and by default we&#39;re going to set it to an empty array if we don&#39;t have any tags we want to add to this particular thing now for our particular use case we&#39;re always going to want to add tags even though these are optional so we&#39;re going to leave that on like this saying that it&#39;s not actually optional and for the type of this I&#39;m going to say it&#39;s going to be tags and it must be one of those valid tag ideas that I&#39;ve created up here this type right here for valid tags it must be one of those particular types to work so here we go we need to pass along a tag and it must be one of the valid tags that we have allowed this is how we actually have type save tagging we know it&#39;s now going to be one of these three different types of tags being added to this every time we do this caching now I&#39;m going to add that star tag to every single thing I cache so I&#39;m going to take all my normal tags and add in the star tag so now everything that I cach with this DB cache function is going to have that star tag on it so I can easily clear my entire cache just like that now this unfortunately I don&#39;t think will work quite out of the box like this I think we&#39;ll need to do a few little modifications we&#39;ll just come in here with a return type and try to use this DB cache so what we can do is we can go back into our database for our products we have our git products function and I want to wrap this inside of a cache well to do this first we&#39;re going to need to split this into two separate functions to make it a lot easier to work with so I&#39;m going to create a function down here called get products internal and this git products internal function is just going to do everything my normal git products does it&#39;s just going to return all the information and it&#39;s going to take in the exact same props it&#39;s essentially the exact same function but the git products up here is what&#39;s going to do the caching for me so what I want to do is I want to get my cache function we&#39;ll set that equal to calling DB cache and what I want to do is pass it that name of git products inter internal so I&#39;m just going to be calling that particular function right there and I obviously need to give it all the tags that I need now the way that I&#39;m doing tagging is whenever you&#39;re tagging something that&#39;s getting information you always want to tag it as specific as possible so if it&#39;s getting something that&#39;s just an individual ID tag it as an ID if it&#39;s getting something based on a user ID which is what we&#39;re doing here tag it based on the user ID and if it&#39;s getting something globally with no user ID or normal ID then we tag it as a global so in our case for our tags here we want to give a user tag because we&#39;re doing this for a user ID and we know that we&#39;re doing this specifically for the products table so I&#39;m going to say cach tags product so now we have our cache function and what I can do is I can return Calling that with my user ID and my limit just like that so the nice thing about how all of this works is when we do this caching with our key Parts this is going to be caching the user ID and limit so if we try to call this function with a limit of five or a different user ID it&#39;s going to be a different cache but if we call it with the same user ID and the same limit it&#39;s going to hit this cache and it&#39;s going to get the information from there now the reason I&#39;m saying that I don&#39;t think that this will work as we expect is because right now the type that&#39;s being returned from here is promise of any and that&#39;s because this unstable cache is actually a generic so we need to convert ours to a generic as well which is a type T and this needs to extend whatever the type of call back is inside of here if we look at what the type of call back is it is this right here so we need to extend this specific type to make this the same thing so I&#39;m going to put the extension right there for our specific type so T is extending that type and then we can just say everything for our parameters and for this function are using that type of T so now if I give that a quick save and we go back to that product section we should hopefully see here that now this Returns the correct type as you can see it&#39;s returning all of our type information so everything has been typed properly by setting up that generic so now every single time we get information from our database we first need to create the internal function that does the actual call for us and then this wrapper function all this does is make it so that we get proper tagging for example a user tag and so on and we just call the function and pass it on so this is really just saying hey get the information from the cache and return it to the user otherwise if it&#39;s not there call this particular function so now we&#39;re caching things as specific as possible again user tag ID tag or globally now we need to make sure we clear that cache every single time we make changes to these spec specific things so for example in this create product function after I&#39;m done creating my product I need to do some revalidating of my tags down here so I would need to revalidate a tag for like my user with the specific user ID you know that I have inside of here I would also need to make sure that I do this for whenever I have a single ID I need to make sure I get the global one as well there&#39;s a lot of things I need to revalidate every time I make a change to something so I&#39;m going to create a helper function that allows us to do that much easier so I&#39;m going to go back into that cache create a brand new function and this one is called revalidate DB cache and all this is going to do is take in the tag it&#39;s going to take in a user ID and it&#39;s going to going to take in the ID and for typing of this information the tag is going to be required it&#39;s going to be that key of type of cache tags but my user id well this is going to be a string that&#39;s optional and my ID that&#39;s also going to be an optional string so now what I can do inside of here is I can make sure that I&#39;m always revalidating my tag so I&#39;m going to revalidate my tag and this is going to be for the get Global tag I&#39;m going to pass it in my tag so there we go whenever I do this revalidate database cach it always revalidates my Global cache so if something requires all of my global data it&#39;s going to make sure that no matter what happens it&#39;s revalidated then if I have a user ID that&#39;s not null well then I want to revalidate a tag so we can say revalidate tag and this is going to get user tag for my user ID and my tag so now if the thing that I created for example is a new product for a specific User it&#39;s going to say hey anywhere that I&#39;m caching information for a user and for products why don&#39;t you revalidate that as well which is really convenient because this get products function is something that specifically gets products for specific users so when I create a new product it&#39;s going to revalidate this as well so it&#39;s making sure that that updates the information that&#39;s why when we put a tag on our information that we were getting from our database we put the most specific tag possible and that way whenever we revalidate a cache we revalidate all of the different caches from the least to the most specific that way the things that need revalidated only get revalidated when they actually change now I can do the exact same thing here with my ID so I can come in here that would be ID and this is going to be an ID tag there we go now we have the ability to revalidate our database cache and we can just use this function anytime that we change our database we can call this function and it&#39;s going to be doing all the hard work for us so here I want to reval validate our database cache I want to get our tag make sure I import this function there we go and for the tag I want this to come from our cash tags. products I also want to specify a user ID and I want to specify ID that we can pass along as well so the way we can get that is just from here I&#39;m already returning the ID let&#39;s just go ahead and return the clerk user ID which we&#39;ll just call user ID as product table. user ID there we go so now I can just say that I want to get my new product. ID and here I want to get my new product. ID and this one should be user ID so now this is going to revalidate all my cach information for me every time I create a product I can do the same thing down here and delete I want to just make sure that I revalidate my database cache and I want to get that new product so I&#39;m going to do the same thing up here where I did a returning field down here I&#39;m going to throw in a quick returning Actually I don&#39;t even need to throw in a returning because it already has the user ID up here so I&#39;m get my user ID and my ID I&#39;m already passing that information in so I don&#39;t even need to bother with the returning I can just revalidate my cache because I did a delete but again only if my row count is greater than zero so just like that I&#39;ll only recache if or revalidate my cach if things actually change so let&#39;s minimize that down minimize this down and we can minimize this down and we can kind of do a little bit of a high level overview of exactly what happened so whenever we do anything that modifies our database for example we delete something or recreate something what we do is we make sure we call revalidate database cache and we pass it along all the information we have so for example when we delete a product we know exactly what user that was for we know exactly what the idea of the product was and we know what thing we&#39;re tagging that as in our case it is a product so we&#39;re to revalidate all the different tags the individual ID the user ID and the actual tag for the overall Global products then whenever we&#39;re trying to get information if we&#39;re getting information for an individual user we&#39;re tagging that as a user if we&#39;re getting information based on a single ID we would tag that with the get ID tag and if we&#39;re getting information generally with no user or no ID we just tag that as a global tag then we guarantee that anytime that we&#39;re accessing information it&#39;s going to be the most up-to-date information and it&#39;s going to be cached if it hasn&#39;t changed recently this is the best way to deal with next jss cache that I found and the only other thing that we need to do this is just something that&#39;s currently a problem with nextjs 14 nextjs 15 fixes this is inside of our next config inside of our experimental we need to make sure that for our stale times on the dynamic pages is set to zero because we don&#39;t want any Dynamic pages to be cached unnecessarily because that&#39;s caching our Pages not our data everything we dealt with was caching our actual data and now this is actually going to make it so our caching Works flawlessly so let&#39;s go ahead and create a brand new product real quick so I can come in here type in some information doesn&#39;t really matter what any of this is there we go click save and you can see it&#39;s going to bring me to this page that doesn&#39;t exist but if I navigate over to my dashboard you can see that in just a second it&#39;s going to load and all my products are there if I then want to delete a product for example I delete this product click delete you can see it successfully deleted my cach was invalidated so it refetch my data for this particular page it all works flawlessly and the best thing about this system is it&#39;s so easy to use all you need to do is think okay am I creating something for example if we go down into our database for our products am I creating something if so revalidate my cach am I getting information if so get it based on whatever the most specific tag is possible and that&#39;s literally all you have to think about when you deal with this caching and everything else will work with for you flawlessly that&#39;s the thing that I am really proud of in this application I think is applicable to pretty much any application you can build and setting it up took a little bit of time but using it is incredibly easy now before we forget I want to make sure that inside of my database section for subscriptions we do the exact same thing here I want to revalidate my cach so revalidate DB cache and again what&#39;s the most specific information we can get well in our case we can get ID and user ID information from here so I just want to make sure I put in a returning into here make sure this is my data just like this and I should probably call this like new subscription or something like that there we go so we&#39;re getting our new subscription and the information I want to get is the ID which is my user whoops subscription ID and we want to get the user ID which is just user ID user subscription table. clerk user ID so now I can revalidate my cache I have my tag which I need to actually add to the particular thing because I don&#39;t have a tag for user subscriptions yet so all the way up here user subscriptions we&#39;ll just call it subscription is subscription there we go then down into here I can say tag is going to be cash tags whoops cach tags. subscription my ID is my new subscription. ID and then finally we have my user id which is new subscription. user ID now I do want to do a quick check if new subscription equals null then I don&#39;t want to do this so if it&#39;s not equal to null then we can run this code right here there we go now let&#39;s just make sure we throw in on a weight up here make this an async function and we can return our new subscription back to our user and then we can make sure I&#39;ll just search to make sure that we&#39;re not messing anything up where we used this so here we&#39;re just awaiting it we&#39;re not waiting for any information back that works fine lastly we need to make sure we do the same exact thing with our delete user to make sure we&#39;re doing all of our caching properly so this is going to give us essentially an array of data based on what we&#39;ve deleted and so on so we already have the user ID I just need to get the ID of the things that we&#39;re deleting and we&#39;re deleting multiple different things so this is going to be by far the most complicated section we&#39;re dealing with so first of all in our returning section I&#39;m going to just throw in a quick returning here and I want to return just the ID so we&#39;re going to say ID is user subscription table. ID same thing down here I&#39;m going to do a returning on my products drop that in right there and this is product. ID there we go then what I want to do is I want to get all my information being returned back to me so we essentially have our rows for our user subscriptions and we have our products that are being returned back to us so let&#39;s come in here this user subscriptions requires us obviously to throw in a quick await here make this an async function there we go so now this user subscriptions is essentially an array we can Loop through each one there should only be one but we&#39;ll just Loop through them just in case and we&#39;ll come into here and for each one we&#39;re just going to revalidate our DB cache so revalidate DB cache the tag is going to be our cash keys or cach tags. subscription our ID is our subscription let me make sure I get this sub we&#39;ll just call it sub sub. ID user ID that is just our clerk user ID that we got from up there so we just Loop through all of our user subscriptions do the exact same thing for our products so for our products for each product we want to make sure this is revalidated our cash for our products there we go and this is is by far the most complicated of all the ones that we&#39;re dealing with finally we can return down our information if we really want so we can say user subscriptions and products just in case we want to use that information anywhere else and now that we have that set up setting up our future functions is going to be so much easier because we don&#39;t have to go back and reimplement everything but now we have a super bulletproof caching system implemented so we took a pretty long detour getting all this caching setup but now we can actually work on the edit page for our product so when we click here to edit a product now we can finally work on this page so the very first thing that we want to do is go into our application we want to go into our dashboard into our products we&#39;ll create a brand new folder this one is going to be for a product ID and then inside of there we obviously want to have our edit page just like that so export default function edit product page now this is going to take in two separate sets of parameters we have our prams which is our product ID as well as our search prams and that&#39;s because if you remember when we created a product we actually redirect them with the tab of country so we can go directly to the country page but by default we&#39;re going to bring them to the details page and this just allows us to choose what page they go to because we&#39;re going to have a tab based design now the next thing I want to do is I want to get my user ID and we can get that from off and again I&#39;m going to get the redirect to sign in so if my user ID is null we can just redirect them to that signin page then finally I want to get my product and this is going to be calling await git product and we don&#39;t want to call git products we want to just get a product for an individual ID and for a user ID because we want to make sure that the user has access to this particular product so we&#39;ll come in here with an async function and we can create git product and this is where all that caching stuff is going to come in really handy so very first export function git product that takes in an ID which is a string and a user ID there we go make sure I actually type that properly so I can get rid of the type from here there we go and this function is essentially going to do the same thing as this function but just call a different function internally so we want to call the get product internal and we want to pass it along all these props right here so I&#39;m just going to copy our props and we&#39;re going to paste them down now again when it comes to tagging you always want to do the most specific tag so in our case we want to get an ID tag because that&#39;s the most specific tag here that we can do and we&#39;re going to paste in the ID just like that now the query for that git product internal is going to be very simple I mean it&#39;s almost going to be exactly the same as this function so I might as well just copy this down get product internal is going to take in an ID and a user ID which is an ID that&#39;s a string and a user ID which is a string and then instead of finding many we want to find the first one and obviously don&#39;t pass in any limit or order by so we&#39;re just going to be getting the very first product that has both the ID and the clerk ID so equal product table. ID is equal to our ID and then make sure we import the and function from here there we go get all my parentheses closed off give that a quick save so now essentially where our clerk ID and our ID are equal let&#39;s call this ID column just like that here we go so when our ID and our clerk ID are equal we&#39;re going to be getting a particular product and we&#39;re returning that right here so now we have that set up you can see with the caching that was very easy to do and the nice thing is automatically it&#39;s going to be revalidated with all this other stuff we&#39;ve already done we don&#39;t have to worry about now that we created a new page going back and changing all of our revalidations again it&#39;s all handled for us automatically so back to that edit page we can import this function there we go and it looks like that was correctly imported my user ID is string or null here if to make sure we return there we go that gets rid of that and we get a product right here being returned to us obviously this product could be to find though so our product equals null then we just want to return not found just like that let&#39;s make sure we import not found and now for our actual edit page to be able to return the information that we want I first want to make this a page with a back button just like we kind of had before so for this I want to have my back button hre equals SL dasboard SL products and then I also want to make it so my page title is equal to edit product then inside of here we&#39;re going to be using tabs now Tabs are something we need to import from Shad CN so come in here we want to add tabs give that a quick second to actually import everything for us there we go so now we should have our tabs be able to be imported directly for us and by default our default tab is going to be whatever our search pram tab is so search prams actually I think we just call tab just like that there we go now we&#39;re getting our default tab oops default tab actually it&#39;s default value there we go that&#39;s why it wasn&#39;t working now we can get into our tabs list make sure we import that from the right location I&#39;m going to give this a class name of background and I&#39;m going to do 60% op opacity just so it&#39;s going to look relatively good in place and now we can put each of our individual tabs in here which are tabs trigger so for each trigger we give it a value this is like the key so in our case details for example for the det Details page that&#39;s what our default is and then we give it a label of details now we can do this for all of them so we have country country and we have our customization and here customization give that a quick save and you can see we get our three different tabs and we can toggle between them and we can display different information for each of our individual tabs so after our list we&#39;re going to have to do tab content where it has a specific value for example details is going to be the value for this this one and let&#39;s just say it renders out details now we&#39;re just going to copy that down make sure I spell that all properly there we go copy that down we&#39;re going to do this one country and then this one customization so now you can see as we toggle between them we get different information being shown I just need to make sure I spell customization properly there we go and now you can see we get all of our different tabs showing our information now obviously I want to show much more complex information so I&#39;m going to create essentially custom components so for this one we&#39;re going to have our details tab which is going to take in all the information for our product now I&#39;m just going to put this component directly in line and it&#39;s very simple it&#39;s going to take in a product with all of our product information and render out a basic card so let&#39;s just import all the different things related to our card you can see that the card is honestly incredibly simple there we go we have extra large text product details and we&#39;re rendering out our product details form and we&#39;re passing along the product for our default value so let&#39;s make sure get this spelled properly details tab there we go and now I just need to make sure that this accepts all of our product details so let&#39;s go down to that form open it up and by default this is going to take in a product optionally and for the type of this we come over here we can just copy over essentially what the entire type is so I&#39;ll just paste all that in there there we go and I want to make sure that this is optional so I&#39;m going to pass it in saying that this is optional that this comes in there and now we can use this for our default values so if we have a product then we&#39;re going to use our product otherwise we&#39;re going to use this as our default values so I can just use the double question mark symbol here and that&#39;s going to use by default our product for our default value otherwise it&#39;s going to use this information but our product needs to be slightly modified because the description here is string or n and this essentially determines it needs to be either string or undefined so what we can do here is take all of our product properties and change the description to be product. description or we can change it to be an empty string just like that there we go so now I need to essentially go back to how I had this before where I said product if we have a product then we render this out otherwise we render this out so by default we use our product if we have one otherwise we use essentially all the information that&#39;s defaulted to just a bunch of empty strings so this should hopefully fill in our default values if I refresh you can see it fills them out now we just need to make it so we actually update our product if we have one so here I&#39;m going to get a variable called action and if product is equal to null then we&#39;re going to call out to create product whoops create product otherwise we&#39;re going to call update product I&#39;m going to bind the ID of our product to that so we&#39;ll say null product. ID there we go and then down here where we call create product we can just call Action instead and all we need to do is implement this update product function so where we have create product we going to copy this paste it down I&#39;m going to call this one update product and essentially do the exact same thing that I did in my create but instead of creating I&#39;m obviously going to update so the really nice thing is most of our code stays the same this gets changed to update product DB so up here we&#39;re going to say update product as and paste that in we&#39;ll create that function in just a second there is an error updating your product and then instead of redirecting the user we&#39;re just going to send them down essentially a success error message so error is going to be false and then we&#39;re going to have a message that says product details updated there we go so now that they know it was updated and we don&#39;t even care about getting the ID back because all of our cach invalidation is going to take place in this update product DB function so now we just need to create that function so inside of here we can export a asynchronous function called update product there we go I&#39;m going to put that in between these two and for this update product it&#39;s going to take in a few things first of all we&#39;re going to take in our data and this data is just going to be the same as our insert data but in instead of being a full thing it&#39;s actually going to be partial because we can update just one field we don&#39;t have to update all the fields then we&#39;re going to be passing in the ID as well as the user ID that we want to update this for so ID is a string and user ID is a string as well so this is essentially our data to update with and this is the wear clause for how we want to update this then we can just call this to update our database so I&#39;m just going to copy this code over because it&#39;s rather straightforward db. update on our table we want to set our data to whatever we pass in here and we want to only do it where the product table clerk ID is equal to our user ID and ID is equal to our ID if that happens and we&#39;re able to successfully update things so we can get from here our row count so if row count is greater than zero well then that means that we had a successful update so I can come down here row count greater than zero and then I can just revalidate our DB cache and I want to do it over my tag is my cach tags. product I want to do it here where my user ID and my ID are based on what I pass in this should say products and there we go that&#39;ll revalidate all of our cach in information for us and we return true or false whether or not it successfully updated everything so now we can save this cache file because looks like I forgot to save it for some reason now into our actions though that&#39;s where we really want to be come to here oops there we go this update DB is going to take in the information we want to update so in our case it&#39;s just our data and then we&#39;re going to pass along our ID which is going to come in here and our user ID just like that and to be able to get our ID information we need to make sure that we pass that in with our update product so we&#39;re going to say ID is a string is a very first parameter that way we know which product we want to update then we&#39;re just going to say is success is equal to that we can come up here error message is equal to again just so I don&#39;t have to type this out multiple times there we go error message and then we can say our success right here opposite of that obviously error is the opposite of if we have a success and then we can say is Success then we want to render out that it was successful otherwise our error message there we go that&#39;s all we need to do for the entire update product function now what we can do is we can go and make sure all of our code is working so inside of our components product details we need to make sure that we import this function so get it from the there we go that updates it looks like it&#39;s working fine no more errors in here let&#39;s refresh our page and let&#39;s just try changing the test name to test name two click save you can see product details updated and if we go back to our product page this is bringing us to the overall products page which we still don&#39;t have we&#39;ll go to the dashboard you can see it looks like it&#39;s not actually updating everything properly it still says test name and when I go to edit you can see it&#39;s still not properly editing this properly let&#39;s go back make sure yeah it&#39;s still not working let&#39;s check our database to see if that&#39;s working cuz it could be something that&#39;s wrong with our caching so let&#39;s just bring this over check into our database we&#39;ll go to our products table give this a quick refresh and we should see that the name is test name 2 so it does look like it&#39;s updating properly we just have a problem with caching so let&#39;s bring this back to being a little bit bigger here what we need to do is on this page we&#39;re essentially calling the git products function so let&#39;s look at our git products function to see how the cache for that is working I most likely just implemented something slightly wrong in my caching so inside of here we&#39;re going to look at git products and git products is based off that user tag right there same thing with Git products so most likely our update product is where the issue is coming in revalidating our cach for the products tag user ID and ID that does look correct let&#39;s make sure here we&#39;re using the products tag here for our get product we&#39;re using the products tag so that again should be correct and we should be revalidating these things let me make sure that I actually implemented the cache itself correctly this looks like it&#39;s passing along all of our different tags that seems correct and our revalidate cache function let&#39;s make sure that is correct as well you can see here the get user T takes the user ID first then our tag second that is what we&#39;re doing here same thing what we&#39;re doing here that all again looks like it&#39;s 100% correct let&#39;s just give our page a refresh see if it implemented it no it&#39;s still not working properly the next thing that we can look at to really help figure out if this is a caching problem is inside of drizzle we can actually log every time we make a query so I can set my logger to true and now if I look at my logs inside of here I just come up there now we should see a log inside of here every time I actually make a quer so if I refresh my page you can see I got no log showing up if I go to my analytics page that showed analytics back to my dashboard you can see it&#39;s getting the dashboard page but there&#39;s no database queries being made so it is something to do with our caching the next step if you have a caching related problem is just to remove the cach completely so here I can just return Calling get products internal with all the information user ID and limit now if this actually works then it probably is 100% a caching problem there we go that completely updated it so we definitely have something wrong with our cash being stored right right here this is why it&#39;s really handy to have that clear cach function cuz maybe there&#39;s something that&#39;s currently cash that we need to get rid of so I&#39;m just going to call clear full cach right here give this a quick refresh that&#39;ll clear out everything inside of our cache at least it should but you can see it&#39;s still getting us the old information so I&#39;m guessing why this is being cached here is because it&#39;s getting us the information from before we properly set up our caching while we had it halfway implemented so I&#39;m going to do is I&#39;m just going to close out of our entire application and delete the entire folder this will get rid of anything that&#39;s cached at all in your application now we can just run this application back up and we can give this a quick restart again and hopefully now we&#39;ll see that when we refresh the page that it will get the correct name and when we update it will also still give us the correct name so test name two let&#39;s go ahead and we&#39;ll change this to three give that a quick save it looks like it&#39;s saved properly go back to our products and it looks like it&#39;s still caching incorrectly the only thing I can think of is we need to check our update product function and yep sure enough I have this set to less than instead of greater than stupid mistake there&#39;s nothing wrong with our caching which is Le a good sign when I refresh we should hopefully see that this will be updated as soon as I make a new update because now it&#39;ll revalidate my cach so let&#39;s change that to three click save it was saved go back and now it is set to three so that was just me being dumb essentially why that didn&#39;t work so you shouldn&#39;t hopefully have that problem if you don&#39;t flip your greater than sign so now we need to work on our country and customization tab because the details tab luckily was really easy so let&#39;s get that back to that page that we were on I&#39;m just going to close all of our tabs so we have something a little bit more fresh to work with over to that edit page and I&#39;m just going to copy down what that country tab is going to look like CU it&#39;s almost identical to what we have up here we essentially have the country groups that we&#39;re going to be getting we&#39;ll implement this function in just a little bit we have a card description which kind of describes what this particular page is doing and then we have our form which again we need to create so very similar to what we have up here we just have essentially a title and description and a form and that&#39;s what this is right here so all we need to do is just take our country tab pull it up into this section country tab need to pass it along a product ID which is our product ID and a user ID which is our user ID and now we should hopefully see we get our country discounts with obviously nothing being rendered because we need to get all the information for our country groups so we need to essentially implement this function to get our product country groups and this needs to get us quite a lot of information so let&#39;s go ahead we&#39;ll copy that to implement it and it&#39;s going to be implemented in the same place get product is implemented so it come up here we&#39;ll just do it all the way at the very top why not export function get product country groups this takes in a product ID and a user ID pretty much the exact same thing we had here there we go and then what we want to do is make sure that this is product ID and then inside this function just like we&#39;ve done for all these other functions essentially we do the exact same thing so we take our props which are these right here pass them into the cache function and make sure we call the internal version of this function and then we need to set up all of our different tags now for now I&#39;m just going to leave this tags blank because we&#39;re going to come back and figure out what the tags are after we implement this function because really it&#39;s hard to write the tags unless you know what you&#39;re using inside the function so here we&#39;re going to create a function it&#39;s going to take in a user ID product ID make sure that we get those typed properly there we go make sure I spell them properly too and now we can implement this function so for this function what I want to do is I want to get all of the groups because essentially let&#39;s say there&#39;s 10 different groups group 1% or 10% 20% 30% 40% all the way up to 100% if there&#39;s 10 different groups I want to get all the groups and all the countries for the groups and I want to get any discount codes that are currently associated with those groups so the very first thing I need to do is just make sure that the person has access to getting all of the information for the country or for the product sorry so I can do that by very simply just calling the get product function I&#39;m going to get the product for a specific user and as long as I have access to that product it&#39;ll return me a product otherwise if it doesn&#39;t it&#39;s going to return to me an empty array this is going to guarantee that the user has access to this information then I can get all of my data and this is going to be coming from calling db. query and I want to query on my country group table because for each group I want to create a row inside of this section so my country group table I want to find many essentially I want to find all of them so I&#39;m not even going to add a wear Clause because I want to find every single group inside of here and for each group I want to get specific information for example I want to get all of the countries and for each country I want to get specific columns the only columns I care about are the name name and the code column because I want to be able to use the name to display what the country name is and use the code to render out a flag for that specific country so I got all my country information the next thing I want to do is get all the discount information so for country group discounts inside of here I&#39;m going to get a bunch of columns and for each column I just want to get the coupon so coupon is true and I want to get the discount percentage we&#39;ll set that to true so I want to get what is the coupon and discount that the user set for this thing that&#39;s relatively straightforward then I want to set a wear Clause so here I only want to do this where my product ID which I&#39;ll just specify as ID for the column name I want to do that where it is equal to whatever product ID I pass into here so let me make sure I put that inside a parenthesis so it&#39;ll actually render properly there we go equals and I want to do where my product ID is equal to that ID just like that so here essentially what I&#39;m doing is I&#39;m getting all of my country groups and for each country group I&#39;m getting individual countries for each of them so if this country group has seven countries it&#39;ll give me all those countries and then I want to get the discount the user has associated with that country if they have one now they may not have one but that&#39;s okay we&#39;ll just set the limit to one and if they don&#39;t have one it&#39;ll be undefined so now we have our country group discounts and our country and that gives us our data and if we look at the type for this data real quick we hover over this you can see we get all the information for our group we get all the information for the countries and we get all the information for the country group discounts but again this could be null so what I want to do is I just want to map through my data return only the things I need in an easy to use format so for each group I want to return this information so we&#39;ll say return I want to get the group. ID I want to get the group name I want to get the recommended discount percentage which is just group. recommended discount percentage I want to get all the countries which is just group. countries and then finally I want to get whatever discount is associated with this which is just the group. country group discounts and I want to get the very first one so just say at zero so if I give that a quick save that should make everything in this file work properly now we can figure out what our tags are going to be and if we look down here the things that we&#39;re querying our our product we&#39;re quering our country group table and we&#39;re quering our countries themselves as well as the discounts now the discounts I&#39;m associating with the project or the product sorry because it&#39;s on the product edit page so this is essentially a product this is a country group and this is our countries so what we can come up here to do is we can get a user tag and that&#39;s going to be specifically for the user ID that we pass in here and we want to do it for our products then the next tag that we need to do is actually going to be a global tag and that&#39;s because the user doesn&#39;t have individual country groups or countries these are Global to every single user you notice when we do our filtering there&#39;s no filtering on the countries and there&#39;s no filtering on the country groups we&#39;re getting all of them so that means it&#39;s a global tag so ctags do countries and we need to do the exact same thing for our country groups and we should just make sure we add those t tags so we can come in here this one is countries and Country groups just like that so now that should hopefully clean up all those errors give that a quick save you can see we&#39;re doing the tagging just like we want and actually I can make this more specific because I have a product ID so I might as well get the ID tag based on our product ID just to make it as specific as possible so now I can actually use this let&#39;s minimize all these functions down to make it easier to work with come back to here where I&#39;m getting my product scroll all the way down and I should be able to import this function and that&#39;s going to give me all of my essentially country group information the ID name the recommended discount the all of the countries and the individual discount if there is one associated with that now with all that information I can go ahead and build out this form with my ID and with that country groups so let&#39;s create this function inside of our forms folder this is called Country discount form. TS and that&#39;s actually country discounts and make sure it&#39;s TSX I&#39;m going to paste in just the typing so you can see here this is the same type we had from before just cuz it&#39;s easy to work with I don&#39;t want to have to type that out for you and now we need to set up our form so we can say form is equal to use form just like that I want to call that function and let&#39;s make sure that we import that now before we do that I want to go over here and make sure everything&#39;s imported properly so let&#39;s import this function that we just created and it looks like we are getting an error here and that&#39;s because this is a type of undefined that&#39;s not definable as null so let&#39;s just change this to undefined there we go that should clean that up and we can even just make this an optional property that&#39;s even easier that should clean up all of our different errors and if we just make sure from here we return something there we go there we go now we got no more errors in this file which is perfect so now we can go ahead and actually start implementing this form so we can say Z from Zod we want to infer the type of and we want to create a schema so we&#39;ll say product Country discount schema just like that and then inside of this use hook form what we can do is we can pass along the resolver which is just going to be a Zod resol that takes in that exact same schema and then the next thing we can do is our default values now before we go about defining these default values let&#39;s go ahead and create our schema so schemas inside of products here we can export a constant for that name and this time we&#39;re going to return an object and this object is only going to have one property this property is our groups and this groups is just going to be an array so we&#39;re going to return array essentially of different objects so we&#39;ll say array of Z doobs and each of these objects is going to have the country group ID this is the ID for each group that we&#39;re associating with this with so we&#39;re going to have a string minimum of one and this is required this should never be missing though because we&#39;re going to make it a hidden field in our form the next thing we need is our discount percentage and our coupon so I&#39;m just going to copy those over paste that down so our discount percentage is going to be a number the maximum value is 100% minimum value of 1% or we&#39;re saying that it can be not a number and in the the case that it&#39;s not a number what we&#39;re going to do is convert that to undefined and this is optional now I&#39;ll get to the point of why this can be optional in just a second the same thing with coupon this can also be optional now there&#39;s some other refining we&#39;re going to do here in just a little bit but I&#39;m going to leave that off until we build our form because then it&#39;ll make a lot more sense so right now our form is just throwing a bunch of errors and not doing anything but as soon as we start importing different stuff we import this let me make sure that this infer is coming through properly I believe this may just need to say type of in front of it actually that obviously does not need to have type type of I&#39;m just missing one of my angle brackets over here that fixes the problem there we go now we have our default values that we can work on implementing as you can see the only thing inside of here is our groups just like that but it does look like we have some errors going on that&#39;s because we need to make sure we pass this inside of an object there we go that solves all those errors and now you can see that the only thing we have inside of here is groups so to make those groups we can just take our country groups that we&#39;re already having passed in and we can map through each of the groups and we can Define them exactly like we want so we come in here we can return an object and this object needs to have a country group ID well that&#39;s just our group. ID that one&#39;s relatively straightforward we need to have our coupon that again is pretty easy that&#39;s just going to be our group. coupon that&#39;s going to come from our discount so discount. coupon but again this can be undefined so if it&#39;s undefined we&#39;ll pass along an empty string then finally we need to do our discount percentage and this is where it gets a little confusing so up here I&#39;m going to say that our discount is equal to and first I&#39;m going to get my group discount and if we don&#39;t have a discount then what I&#39;m going to do is I&#39;m going to fall back to my recommended discount percentage so I&#39;m either going to use the currently defined discount by the user or fall back to whatever the recommended discount is then for my discount percentage if my discount is not equal to null well then I&#39;m just going to take my discount and multiply it by 100 because our discounts in the database are stored between 0 and 1 and in the actual form we&#39;re storing them between Z and 100 so it&#39;s easier for people to understand otherwise we&#39;re going to return undefined here as the discount percentage now if we give that a quick save that at least gets our default values for our form now we can actually render out what our form looks like so we&#39;ll get started with the basic form stuff we use the form component from the form Library we need to have an onsubmit function there we go and that is going to take in values which is z. infer and that&#39;s the type of our product Country discount schema so let&#39;s just paste that in there so now at least we console. log our values out if we really wanted to so now we have all that information we can close off our form and our other form to get our actual thing working and now inside of here I just want to Loop through each one of our country groups so country groups. map through each group and for each group I want to render out a card because this is going to be a card-based layout and the key is the group. ID there we go and inside the card I don&#39;t even need a header I just need the card content so for our card content I&#39;m going to add a class name here I want to make sure I import this so we can actually use class name pading on the top of six to give it some space on the top we&#39;re going to flex with a gap of 16 and our items in the center and that&#39;s because the left side of this is going to be all the flags and the right side is going to be all of the different input Fields so let&#39;s put in a div that&#39;s going to render all of our left side content so we&#39;re going to have an H2 which is our group. name just like that so if we give this a safe go over to our country Tab and we make sure we have everything imported properly let&#39;s just give this a refresh to make sure again my problem is I need to make sure I use this as a client component now if we go to our country we see that we currently aren&#39;t actually getting anything rendered out and that&#39;s because we don&#39;t have any country groups yet so one thing that I&#39;m going to do before we worry about adding country groups is I&#39;m going to go back to this page I&#39;m going to pass in essentially a placeholder value so we know that we have some countries that we can store inside of here which is an array and inside this array we&#39;re going to have a code so for example like us and a name United States and let&#39;s just do another one inside of here code is going to be I in and we&#39;re going to have the name be India there we go so now we have our countries being defined let&#39;s make sure that we also Define our ID it doesn&#39;t really matter we&#39;ll just put in something like that we&#39;re going to need a name this is group one we&#39;re going to need to have here our recommended discount percent let&#39;s just say it&#39;s going to be 0.1 so that&#39;s 10% and then finally our discount if we have one so we&#39;ll say the coupon is high and the discount percentage is going to be2 so we can obviously play around with taking this discount off and not but now you can see we have a group showing up inside this section and then we&#39;ll go about actually making it so we have all of our groups but for now I want to get the form working pretty well so let&#39;s get our group name in place I&#39;m also going to drastically strength this down so for our class name text muted foreground text small font semi bold and we&#39;ll put a low margin on the bottom of two and that&#39;s because directly below this is where we&#39;re going to put each one of our flags so we&#39;re going to say flex and a gap of two and we&#39;re going to do a flex wrap now inside of here we just want to Loop through all of our different countries so countries. map for each country I just want to render out what that flag is going to be and to do that we&#39;re actually going to install a library called react country flag so we can come in and we can use the react country flag component let&#39;s just make sure that we import this so all the way at the top here we&#39;re going to import from the react country flag Library you can use whatever Library flag you want really this just downloads a bunch of svgs and what we can do is we can say that our country code is going to be country. code and then we can specify we want to use an SVG and now if we give that a quick save you can see we get the US and India flag showing up now there&#39;s tons of different libraries you can use for this for example another Library you can use is just a URL right here for a source for an image so if I import this image from next image give this a save you can also see if I were go to the country tab I now get the flag showing up this way personally I actually like this image source a little bit better and this is just another flag Library this is country Flag icons so if you search for Country Flag icons you&#39;ll get this exact URL and I&#39;m just pasting in my country code uppercase it and then getting the SVG I personally find that these icons look a little bit better on a smaller screen size so I&#39;m going to be specifically using these icons instead of the ones in the react country flag library but again you can use whatever Library you want for this particular use case so now we have all of our flags as well as the group name showing up that&#39;s everything inside this div the next thing I want to do is I want to add a hidden input into our field so we&#39;re just going to say type is hidden and then we can just register this input manually so we can say form. register and this is going to be at groups Dot and then whatever our index is Dot and then this is going to be what the field is which is our country group ID just like that make sure I close off my input and I make sure I import this there we go so now this is just giving us a hidden input at this index I want to make sure I get the index just like this so that way when we submit our form we&#39;ll actually know what the country group ID is without manually having to type it in so there we go we have our group one showing up now we want to create our form Fields off to the right hand side here so we&#39;ll create a div we&#39;ll give it some class names margin left of Auto just push it all the way to the right we want to make sure it doesn&#39;t shrink down and we want to make sure it&#39;s a flex with a gap of two and we&#39;ll do Flex column as well so they can stack vertically on top of each other and the W is going to be minimum so that&#39;s going to make this div shrink as much as possible now there are two things that I&#39;m going to put the first thing is going to be a div that contains all of our different inputs and then below that I&#39;m going to have a form message to display any error messages that I have and this error message is going to be at the root level of our application so form state. errors. groups at our particular index get any root level errors and that&#39;s because when I mentioned that we have extra validation we need to do inside of here that&#39;s what I&#39;m going to put inside this root section right here now what I want to do next is style what our inputs are going to look like so we&#39;ll say a flex with a gap of four to space them out from one another and now I&#39;m going to paste in this input for our coupon you can see this is stuff that we&#39;ve all done a million times before so let me just get all these Imports in real quick there we go oops didn&#39;t get that in there properly there we go so I just have a form field the group is just going to be the group at the index and this is my coupon field so it&#39;s our coupon and the width is going to be 48 we don&#39;t want it to be too big now I&#39;m going to do the exact same thing by copying down another input field as well this one is going to be for my discount and I believe it&#39;s called discount percentage just like that there we go that&#39;s our name this is going to say discount percent aside of here the class is going to still be a 48 width but I want to change a few things about this for example I want to specify how my value is going to be set that should just going to take my field. value or it&#39;s going to set it to an empty string and then my on change what I&#39;m going to do here is I&#39;m going to get my e and then I just want to say field.on change and want to specify e. target. value as number and this is just going to make sure that it&#39;s going to convert this number input the string that it gives back to me into a number for me to save then again I have my class with a width of 48 in my case I&#39;ll make this one quite a bit smaller at 24 and then I&#39;ll specify a minimum of 0 and a Max of 100 there we go give that a quick save and now you can see my discount percentage and my coupon and they&#39;re both being set to high right now which is obviously not correct so I have something mislabeled let me just give it a refresh see if that fixes it there we go discount at 20 coupon at high and if I make my screen a little bit larger you can see all the flags are showing up really nicely now if I go over here and I get rid of this discount we should see the coupon goes away and the discount percentage changed to 10 so let&#39;s give that a refresh go to Country you can see discount percent falls back to the recommended and my coupon goes away completely and this is why I made it so that the coupon field is optional and I also made it so the discount field is optional because if you don&#39;t have a coupon you don&#39;t need a discount to be able to be passed in now it does look like I have some issues right here with this showing up is not a number and so on so I&#39;m going to go about and try to fix that right now I think all we need to do for fixing that is here where we&#39;re doing the field value we can say if the field value is not a number then we&#39;re going to render out an empty string otherwise we&#39;re going to render out our field value there we go and also I believe our field value could be undefined so we&#39;ll say here field. value if it is undefined then we&#39;re going to just do whatever is inside of here so this should hopefully just be a number nope it&#39;s actually only undefined there so of course we&#39;ll do a check here if it&#39;s set to null then we&#39;re going to do all this is <PRESIDIO_ANONYMIZED_PERSON> put all that inside of parenthesis otherwise we&#39;re going to render out if it&#39;s not null the field. value there we go and here I should say if it&#39;s not null then we want to do this check here and if it is null then we&#39;re going to print out an empty string just like that there we go so now you can see that that got rid of that problem and to clean up our code a little bit we&#39;ll say if the field that value is not equal to null and if it is not Nan then we&#39;re going to render out field. value otherwise we&#39;ll render out an empty string so if the value is null or it is na an we&#39;ll render an empty string so now we&#39;ll give that a refresh go over to Country you can see looks like we still have a problem and I believe the reason for this is because I need to make sure that this input field is a type of number that should solve all my different problems let&#39;s give that a refresh go over to Country you can see I can delete this I can type in numbers everything&#39;s working perfectly fine I believe I can even simplify this code by bringing it back to that double question mark syntax and following it up with here there we go this should hopefully be much simpler and still work let&#39;s make sure that works come in here delete that type in yes that is still working just fine so a much simpler version of our code so now the final thing we need to do below all of this section after our card content after our card literally after every single thing right before our form ends we&#39;ll just add a button that allows us to save this information import the button and now if we go over to our country give this a save we scroll down you&#39;ll see that we have a save button all the way down here which is exactly what we want we can click save and it&#39;s going to run some code right now all it does is console log out our values so what we need to do is instead of hardcoding this information we need to actually get this information from our database which we&#39;re already doing but right now there&#39;s no data in our database so this is completely empty so we need to write some code that allows us to import all of our different country groups into our database because this is information that never changes really unless a country drastically increases or decreases its purchasing power and it&#39;s the same for every user on our site so first of all we need to get all of the data for the different countries I&#39;m just going to paste in a file here called countries by discount. Json this gives us a name a recommended discount percentage and a list of all the different countries that fall into that group and it does it for every single group of countries as you can see if you want to get this exact file I&#39;ll have it inside of the GitHub repository so there&#39;s all of our countries by the different discount and then what we want to do is we want to create a task so I&#39;m going to create a folder called tasks just like this and inside this tasks folder I&#39;m going to create a file called update country groups. TS and this is a task that I can run that&#39;s going to read all the contents to this file and update all of my country groups based on that information so I&#39;m going to create a function called update country groups I&#39;m going to create a function called update countries and this allows me to update both of these different sections so I&#39;ll just call this in a wait and a wait just like that now you will notice I&#39;m getting an error essentially on all of this stuff I need to make sure I use imports and exports to do all of this so let&#39;s coming down here let&#39;s create the async function update country groups just like that that&#39;ll clean up some of those errors and the very first thing I&#39;m going to need to be able to access is my database so we might as well just import that right into here now you will notice it says top L weight is not valid unless I have some set of es modules or so on being enabled inside my typescript so we can go ahead and enable that so in RTS config here right now we have certain things seeing set really far in the past and that&#39;s because we don&#39;t have a Target being defined this is the Target that our code compiles down to we&#39;re going to say es 20107 that&#39;s the earliest that you can actually do top level weight and there shouldn&#39;t be any code that&#39;s you know relying on 2017 features or Beyond so here we go that fixes our top level weight and now we can go ahead and actually write this function so first I need to get the data I&#39;m going to insert so this is going to be called country group insert data I&#39;m going to set that to countries by discount and this countries by discount is something that I need to import and that&#39;s coming from the SL dat countries by discount Json so I can Loop through each one of these by mapping through each one and for each one of these I&#39;m going to be getting a name and I&#39;m going to be getting a recommended percentage let&#39;s see that is recommended discount percentage there we go and that&#39;s going to give me a function and inside this function all I want to do is return combining those together so name and recommended discount percentage so essentially I&#39;m just removing the countries portion of this information and now I have an array with names and recommended discount percentages that I can insert into my database so I can say my row count is equal to calling DB Dot and I want to insert into my country group table since I have all the information I need for it I want to insert specific values and the values I want to insert is that insert data that I just created now this is actually going to work but I want to make sure that this also works for updating my information so if I run this file twice in a row it&#39;ll still work so in that case I can do an on conflict on on conflict I actually want to update things so first of all you have to specify the target this is the thing you&#39;re searching for in our case whenever our name is the same that means that I want to do an update instead so if my name is the same then I want to update that recommended percentage so here I call the set function and this allows me to set specific things for example we don&#39;t need to worry about the name because we know the name is the same but what we can do is we can say that we want to set the recommended discount percentage and the easiest way to update this is by using this SQL do raw function and this allows you to pass in a string and we can pass in the string called excluded Dot and then we pass in whatever the name of the thing we want to do is so our case it&#39;s the country group table. recommended discount percentage. name so what this fancy line of CSS is essentially doing is it&#39;s saying okay insert into my country group table all this data and every single time you find a duplicate should make sure you update only the recommended discount percent and this excluded dot syntax is just saying hey get whatever the value of the recommended discount percentage would have been for the insert and instead use that for the update it&#39;s a relatively complex line of code but it doesn&#39;t really do that difficult of things now obviously after this we need to revalidate our database cache in our case we only have a global tag to work with so our cash tags. country groups we want to revalidate our cach for that and then what we can do is we can return our row count just like that so this is going to show us all the things that were updated so we&#39;ll say group count is equal to that and we can do some kind of log for example I&#39;ll just copy over the log just like this updated this many group counts and this many countries and here we we can say our countries is equal to that so this is just telling us how many of those different things we updated so first we update all of our groups and now we can go ahead and update all of our countries so this is going to be update countries just like that again it&#39;s going to use this exact same countries by discount array that we have up here so first I want to get our country groups so that is actually going to be coming from our database just like this and you will notice here I&#39;m okay with using my database queries in this specific file because this is code that&#39;s not part of our application this is outside of our application we&#39;re never going to call this code from our application so it&#39;s kind of its own unique entity I want to keep it as separate as possible from the rest of our code so that&#39;s why I&#39;m okay with using a database directly inside of here now I want to get our insert data country insert data is equal to and again Loop through that array I want to use a flat map this time because I want to convert that array of countries into a single array instead of a nested array and this is going to return to me countries and it&#39;s going to return to me the name which is the group that they are a part of now the next thing I want to do is take each one of my countries and I want to Loop through each country so now I&#39;m looping through each individual country and mapping them into their own array let&#39;s get the country group for this country which is just country groups find the group where the group. name is equal to our name make sure I spell that all properly and I can even move that up to here so we can get the country group once for each set of countries and if for some reason our country group is null I want to throw an error this should never happen it should be completely impossible but just in case we&#39;re going to put that error in there then down here I can just return an object that has the name which is my countryname we want to get the code which is just country. code and I believe it&#39;s called the country inside of my array of data and then finally the country group ID is just country group. ID there we go so that&#39;s all the data we want to insert just like up here we essentially need to do the exact same line of code so I&#39;m just going to copy that down but instead of into the group table we&#39;re going to be inserting this into the country table just like that and this is my country insert data and again this is my country table and instead of using the name I&#39;m going to use the code as the uniqueness indicator now here I want to change my name I want to update that from my country table so anytime that I have a code that&#39;s the same I want to be able to change my name and I also want to change instead of here the country group ID so again update only these fields if the code already exist that way if I run this update function multiple times it&#39;ll only update the ones that have changed now down here I want to update the cache for my countries and that should be all that I need to do and now this is going to add information into my database for all of my different countries so now inside my package Json I can just make a script that lets me run this so for example DB update country groups and this is going to run TSX with an environment file ofv and it&#39;s going to run the file inside my source folder inside tasks inside update country groups. TS now I can just run this exact command npm run DB update country groups just like that and that should run my command but of course I have to install TSX first so npmi this is a Dev dependency TSX that allows me to run typescript files without actually doing anything else and now we can click run on that and you can see we are getting some errors showing up again top level weight is not supported with the CJs output format now I just need to come in here change my type to module that should fix that problem now let&#39;s give this a quick run and hopefully that should work but again we&#39;re still getting an error react does not have an export named cache this is unfortunately a bit of a trickier problem to get around and the reason why this cach export is not there is because the current version of react does not have this cash export it&#39;s only available in the canary version it should be out in react 19 which is not quite out yet and the reason we can use it though is because we&#39;re using nextjs but when we run this file outside of nextjs it doesn&#39;t know about that cache so for now the best way to get around this is just to remove everything related to the caching so we&#39;re going to remove the revalidation of our cach here and we&#39;re going to remove the revalidation of our cach here and if we run this function we&#39;re just going to need to make sure that we manually clear out all of our caching information which is not that big of a deal again in future versions of react when this is actually a function that you can use you won&#39;t have to do this but right now we do have to do this while we wait for react 19 so now let&#39;s go ahead and try to run out that file so we can come in here whoops run that file again and hopefully this time it should work as you can see it printed out all of my database queries as well as it said we updated 10 country groups and 192 countries so it did look like it worked just fine now to make sure that we don&#39;t have any caching problems to worry about I&#39;m just going to manually update my cache so inside of whatever country or component I was working on so let&#39;s just come over to this page right here I&#39;m just going to call the Clear full cache function refresh my page that should have hit that function and now hopefully our caches are cleared so now if we go to the country tab it looks like it&#39;s still not pulling in all of our different country groups let me just make sure again we are clearing the full cache calling that function give this a refresh go to this page refresh still doesn&#39;t look like it&#39;s actually clearing the cache and if we check to see if we are hitting the database we refresh our page it looks like it&#39;s not hitting database at all so our cach is not being properly cleared let&#39;s go back to the page we&#39;re on before let&#39;s make sure that our caching is working properly so we can go over to our lib folder inside the cache we should see the revalidate for clearing is revalidating the star tag and every single one of our things should have the star tag if they&#39;re inside of our DB cache but it doesn&#39;t look like that&#39;s working as expected the next best thing that we can do instead of having to worry about figuring out that caching issue because it could just be something that&#39;s stored in the cache from before just delete thex folder that&#39;ll clear out the cache and restart your server there we go that should fix any of those particular problems we were running into now when we&#39;re on this edit page should grab everything from scratch and hopefully we won&#39;t have any caching problems going forward so now in our country tab you can now see that we have all of our different country flags the recommended percentages and the coupon code and that&#39;s for every single group that we have which means that all of our code is working flawlessly and if we click save you should see it allows it to actually save but right now it&#39;s not doing anything cuz we&#39;re not calling any particular function so let&#39;s go ahead and work on calling a particular save function and then I can talk about why I wanted to be able to leave coupon and discount blank because for example what if I don&#39;t want to add a coupon for this group well I want to be able to leave that blank that&#39;s why I left that field as optional same thing with the discount if I don&#39;t include a discount or a coupon I don&#39;t want to include anything for that group the only time I want to throw an error is if they type in a coupon but don&#39;t add a discount obviously in that particular scenario I want to throw an error so let&#39;s write a schema for that we already have our schema I just want to add some validation to that particular schema so inside of our schema I&#39;m going to add a statement for refining that schema so if we look at this code all I&#39;m doing is I&#39;m checking okay do I have a coupon that essentially means that my coupon is not n and the length is greater than zero also do I have a discount code which means it&#39;s not equal to null as well essentially what I&#39;m saying is if I have a coupon code and I do not have a discount then throw an error and I just want to say a discount is required and I want to put that at the root level and the reason I put that at the root level is because when I render out my form message if I pull this down and look down here I&#39;m rendering it at that root level so now if I were to try to save this I can actually demonstrate that by deleting the discount having a coupon I&#39;ll refresh my page so I get the most upto-date information put a coupon on here click save immediately I get an error a discount is required if a coupon code is provided as soon as I put in a discount and then I reclick save you can see that error goes away and it tries to save my form but of course we&#39;re not doing anything when we save our form so that is our next step now this saving code should probably look pretty familiar to you I&#39;ll just paste it in we&#39;re going to call this update country discounts function which we&#39;ll create in just a second and then we&#39;re going to make sure that we&#39;ve render out a toast message depending on if we have a success or an error State given back to us so I&#39;ll come all the way up to the top make sure I say const toast equals use toast there we go so now we actually are able to render out toast messages now we can work on creating this update country discounts so we&#39;re going to go into the actions section so inside of our server our actions for our product export an async function which is called update Country discount and for the parameters I&#39;m just going to copy those over so you don&#39;t have to watch me type them it&#39;s going to take in an ID and it&#39;s going to take in all of our schema data then we can do the same thing we&#39;ve done for create and update and all those other ones I&#39;ll just copy this down we essentially wanted to First compare this to our schema parse the data and if it&#39;s correct we get our data otherwise we&#39;re going to throw an error message there is an error saving your country discounts there we go then after that we can create our insert data and our delete data so this is going to be a little bit complicated I&#39;ll paste down the code and then explain exactly what&#39;s going on in just a second so for each of our country codes whenever we submit our form we&#39;re going to be submitting this entire form so we&#39;re going to submit every single group with every single discount and every single coupon code and we just need to check okay is there a coupon and a discount then we need to insert this data into our database and if there is not a coupon or not a discount we need to delete that information from the database wherever it exists so that&#39;s what this is doing I&#39;m first getting all the rows to insert and then I&#39;m getting all the rows to delete so first of all the insert data I can come down here and for each one of my groups of data so each one of these cards that has a coupon and a code and a group number I&#39;m first checking is my coupon equal to null or my length or my discount percentage or my discount percentage essentially do I have a coupon and do I have a discount percentage if I do insert this into my insert data where I&#39;m just inserting my group ID my coupon my discount percentage of my product and again I&#39;m converting that discount percentage to a number between 0 and 100 so if I have a coupon and a discount percentage add that to the insert rows otherwise just add the ID that I want to delete to the delete row then what we can do is we can actually call our database and we can do all of our inserts and we can do all of our deletes and some of these inserts might actually be updates it really depends so then after we get all of our data grouped between inserts and deletes we then need to call the update country discounts function from our database again because we&#39;re essentially doing the same thing we&#39;ve done up here update country discounts and I want to call the database version again just calling out to that database to handle all the database stuff for us and inside here I want to get all of my delete groups I want to get all of my insert groups so we&#39;re going to say insert just like that and then finally I want to pass it along the product ID and I want to pass it along my user id as well so the product ID I know is just ID just like that and I already got my user ID at the top all the way up here and that&#39;s just to make sure we have all of our different validation and stuff in place and I can just await this function now I need to create this function so we&#39;re just going to go to the file where that function will be defined that&#39;s inside of here export an async function with that particular name I&#39;m going to copy over the actual data types for the things we&#39;re inserting into the data so give that a quick save there you can see we have our delete Group which is just an array of IDs we have our insert Group which is just an array of insert data and we have our product and user ID now inside of here first I want to get our product so we can get our product and if they don&#39;t have a product then we want to essentially return null or return false or something we&#39;ll just return false or whatever and just saying hey we could not update any of this information because you don&#39;t have access to this product if you do have access to this product though then what I want to do is I want to create a batch so I&#39;m going to create a bunch of statements which is batch items and these are going to be of the type PG because we&#39;re doing postgress data here I&#39;m going to get an array of those and I&#39;m going to set it equal to an empty array then what I&#39;m going to do is if I have anything to delete so if my delete group is not equal to null and my delete group. length is greater than zero then I know I have data that I want to delete of course these should not be able to be undefined I don&#39;t know why I have that set to be undefined so we&#39;re going to remove that and essentially we can just check if our length is greater than zero then I want to run code to delete information so inside my statements I&#39;m going to push a new database query so we&#39;ll say db. delete I want to do a delete from my country group discount table and I I want to do it where specifically certain criteria is true so I want to do an and query here I want to do it where my country group discount. product ID is equal to the product ID that I pass in so first of all for the product that I&#39;m currently editing I want to be able to do that particular row and I want to make sure that in an array I want to check my country group discount table ID for the group and I want to check to see if that&#39;s in my deleted group array so for each one of these I&#39;m going to map them to just getting the individual ID so group is group. country group ID so what this code is doing right here is I&#39;m deleting all of the rows from my discount table for this particular product where the ID for the group is inside the array of deleting IDs that I want so essentially everything I marked as deletion is going to get deleted inside of this statement then the next thing I can do is handle my insert group so if my insert group. length is greater than zero then I want to run a bunch of insert code and put push that into my statements so statements. push DB do this one&#39;s going to be an insert in my country group discount table the values is just going to be whatever my insert data is so I think I call the insert group and then if there&#39;s a conflict I want to do a specific update to this information so let me make sure I get my parentheses in the right place and then I&#39;ll explain exactly what this particular line of code is doing so on conflict if for example I already have a row in my database for this product ID and this country ID well then I just want to update my coupon and update my discount percentage that&#39;s all this is doing so it&#39;s inserting new rows but if there&#39;s already rows for that group and that product then I just want to update the coupon and discount that I added into that section so now I&#39;ve essentially created my two statements and if my statements. length is greater than zero there we go greater than zero well then I want to run some code so I can say db. batch that&#39;s going to run all my code going to pass in my statements now this will give me a typescript error because this expects the element to have at least one thing in the array we&#39;ve already checked for that so I can just essentially cast this to be batch item of whoops PG just like that and that&#39;s essentially telling typescript I know that this element has at least one value in the array once that&#39;s done we can revalidate our cash we know what the tag for this is going to be is going to be cach tag. product because anything on the product edit page I consider a product user ID and the ID is our product ID then what we can do is we can return any type of validation that we want from here so for example equals this information this is going to return an array of data actually so we can get from the first one our row count and the second one is going to be a row count value as well but honestly we really don&#39;t care about this information we know that if we ran through all this code that&#39;s really all that we care about it being successful we don&#39;t care about anything else so back in our actions where we had all of our code inside here we should see that we don&#39;t have any errors I just want to make sure I spelled all this right update discounts DB looks like I did spell that incorrectly so inside of the database this should not have DB inside of it there we go that cleansed up our code in here so this is working now here we can import this from the actions just like that that should be the action one that I imported looks like it is and that should be working just fine and this is going to return to some data but it says that this data could be undefined so we&#39;ll make sure that the data is not undefined by at the very bottom here after this runs we want to return error false and then we can put down a message that says country discounts saved so if we give all of this a save come over here refresh our page we should be able to actually set some coupons so let&#39;s say that this one&#39;s going to be C1 for our 60% down here for 40% we&#39;ll set that to C2 let&#39;s actually change it to 32% and down here we&#39;ll create a brand new one with a C3 value so we should hopefully see all these different values when we click save you can see it says our country discount saved we&#39;ll refresh our page go back to here C1 was saved for 60% C2 at 32% and C3 at 12 and if I change this to be like 2% and I resave you can see when I refresh my page it&#39;ll go through and it&#39;ll properly update this that&#39;s why we have that on conflict due update statement so now we can finally move on to the final tab this one&#39;s quite a bit easier don&#39;t worry this this country one was by far the most confusing so what we can do is we can go back to our edit page I&#39;m going to paste in essentially the section for customization I&#39;ll comment out the things that we are not able to handle right now because we&#39;re going to get to them in just a little bit but essentially it&#39;s the same thing we&#39;re rendering out a card with all of our information and we&#39;re getting all the stuff from our database and rendering it out the form so if we give that a save refresh our page you&#39;ll see if I actually make sure I use this customization tab up here import the information we need which is our product ID so we can get that from our product ID and our user ID user ID now you can see it says Banner customization and obviously we can get our information from our database so the very first thing I want to do is handle getting our product customization from the database based on our product and user ID and again we&#39;re going back to the exact same database file to implement this function so export function paste in the name here this is taking in the exact same props and it&#39;s essentially doing the exact same same thing as this function paste that down there we go so all we&#39;re needed to do is just call the internal version of this function there we go now again I&#39;m not sure what I&#39;m going to need for my tags just because I haven&#39;t written this function yet but I&#39;m pretty certain all we&#39;re going to be doing is updating information from our product so I&#39;m going to put the ID tag for the product we&#39;ll come back to that if we need to update it now we can come down to the bottom here and we can put in that function if we want async function get the name of it and again the props are the same as this one so I&#39;m just going to copy the props over so we don&#39;t have to type those out there we go now this function is incredibly straightforward because all we&#39;re doing is we&#39;re just quering our product table and getting the very first product for our product ID and our user ID and we&#39;re returning with that our product customization that straightforward then what we can do is we can return our data. product customization and if our data is null it&#39;ll Return To Us null here so really all the code we&#39;re doing right here minus this wi section right here is exactly the same as getting a product we&#39;re just making sure we&#39;re tagging on the product customization and returning only the product customization from that section so that gives us our product customization that was by far the easiest thing we&#39;ve done in a while and here we can just make sure we import that function and we&#39;ll now have access to that customization and if it&#39;s null we return not found but again this should not be null now the next thing we need to focus on is how we deal with permissions this is kind of something we&#39;ve been ignoring up until this point and to really focus in on the customer ization section we need to focus on permissions because there is a permission for being able to remove The Branding from this and luckily I have a really bulletproof and easy way to handle permissions that I&#39;m going to show you right now so the first thing I want to do is inside of a folder for my server so we&#39;ll go all the way down to our server folder create a brand new file called permissions. TS and inside this permissions function I&#39;m essentially going to export a bunch of asynchronous functions for what we want to do so in our case async function can remove branding there we go and this is going to take in the user ID which is a string so I&#39;m just saying hey can this particular person remove The Branding well the first thing I need to do is if my user ID is equal to null then I&#39;m going to return false and I&#39;m going to make sure that this could be also null this is just making it easier for me to actually call this function because if I don&#39;t have a user ID it&#39;ll always return false this again is just a yease of use thing then what I can do is I can get the tier for the particular user that we stored in our database so we can call user subscription tier with our user ID we need to create this function inside of that DB folder here so we have a create function we need to get a function for getting a particular tier and this takes the user ID which is a string now this function is actually going to piggy back off of a second function I&#39;m going to create called get user subscription and this will allow us to get just an overall users subscription and this again is going to be just like all the other stuff that we&#39;ve done in inside of our application where we have an internal version of it so function just like this user ID which is a string and this get user subscription tier is essentially just going to call get user subscription and give us just the tier portion of it so I&#39;ll actually show you exactly what that code looks like we&#39;re going to get the subscription from here and we&#39;re going to get the tier and return that to the user based on our subscription tiers so our subscription tiers if you don&#39;t remember properly is all of our different tiers free paid and so on and it includes information like can I remove the branding can I customize the banner and so on so that&#39;s essentially what this entire section is going to be talking about now to get this code to work we need to make get user subscription work by making get user subscription internal work so this function is actually a relatively easy function we&#39;re just going to return db. query and we want to query our user subscription table we want to find the very first one where let me make sure I pass in all the information we&#39;re going to need into here we want to get our clerk user ID and the equal functions and we&#39;re going to check to see if the clerk user ID is equal to our user ID so just give me the user subscription for this particular user then inside of here we&#39;re just returning that information and we&#39;re caching it based on the user tag just like that and then if we come down here you can see we get our user subscription tier all we&#39;re doing is getting the subscription if it&#39;s null we&#39;re throwing an error because they should not have a null subscription and then otherwise we&#39;re getting all the data for that subscription based on the tier free basic and so on so now back into my permissions when I call that function now I have this tier that has all the information on what they can and cannot do so I can just call this and return can they remove branding that&#39;s as easy as this function gets it&#39;s actually so straightforward that the next two functions for customizing the banner and accessing the analytics are the exact same lines of code the only thing that changes between them is what I call down here is it can access analytics can customize Banner or can remove branding so that&#39;s what I need to do for this basic set of permissions now back over to here I can just call that function with my user ID and now I know what whether or not I can remove this or not same thing down here if I comment this in I have the can customize Banner function again I call that and I can see whether or not I can actually customize this and I can even move this await statement into here if I really want to just like that relatively straightforward now I just need to create my form itself so inside my forms let&#39;s create a brand new and actually our final form for the entire project customization form. TSX I&#39;m going to paste down the typing information because again this is not super important for you to learn how to type out this is just all the different things that we&#39;re passing into this particular function that we want to use now before we go ahead implementing this function what I want to do is first import this here so at at least know that that is working you can see all the errors were removed which is great now if I refresh this page you can see it renders obviously there&#39;s nothing in our form but it&#39;s working now if we go over and to our schema we&#39;re going to be implementing the last and final schema of our entire project as well and that&#39;s the product customization schema this one&#39;s super easy essentially we want to build to modify the class prefix background color text color font size message that&#39;s showing up Banner container and whether or not it is sticky that&#39;s how easy this entire thing is now if we go back down to our form we can use this schema just like we&#39;ve done with all of our other forms so we can use the use form hook just like we were using before I&#39;ll make sure to import that I&#39;ll import the Zod resolver and I&#39;ll import our schema as well as you can see here we&#39;re using that hook for used form we&#39;re passing along our schema and our default value is just all of our customization and if our class prefix is null since this is the only thing that can be null we&#39;re converting it to an empty string so it works properly inside of our form now we have our form let&#39;s go ahead and get an async function called onsubmit and this onsubmit function just takes this as our type so we&#39;re going to have data actually I think we call it values there we go and then inside of here we can do whatever we want console log our values for now it doesn&#39;t really matter then what we can do is we can go ahead and Define our form just like we&#39;ve done in the entire rest of our application get that from the right place pass in all of our form data there we go and then we need to render out the actual form component itself with all of its different props and these props are pretty much the same props we&#39;ve been using the only difference is I added a margin top of eight and I also have things being laid out in the column direction for Flex actually that&#39;s the same as before but the only difference is a margin on the top of eight and that&#39;s cuz I want to put a banner at the top of this section so I want to show you like what the banner is going to look like this is essentially going to be our Banner for now it&#39;ll just be an H1 that says banner and right now none of this is working because it needs to be a client component there we go so now you can see we have our Banner showing up which will happen in a bit and then we have our form so for our form it&#39;s going to be broken into two halves so we&#39;re going to use a grid with a gap of eight grid columns is going to be one on small screen sizes or on larger screen sizes we&#39;ll set the columns to two and then on our left hand side side we&#39;re going to have essentially our giant message so div here with a class of flex and actually I can completely remove this div because we only have one thing on the side and that is our form field and our form field is going to obviously have our normal properties of control which is our form. control we&#39;re also going to have our name and this is going to be our location message and then finally our render prop for rendering out our field so field render this out and inside of this particular field if I make sure I spell everything properly we have our form item there we go inside of here we have our form label which is our PPP discount message then after that we&#39;re going to have essentially a star that we&#39;re going to call our required label icon this is something I should have also put in the details section because the name the URL are required so let&#39;s go ahead and create this real quick while we can it&#39;s a rather simple component this is something we can use anywhere in our application so I&#39;m going to put it in my normal components folder here required label icon. TSX just like that it takes in no props at all other than it can take in any props really so we&#39;ll say class name and we&#39;ll say all the additional props and that&#39;s just because I want this to be all of the props that you would normally get with the asterisk icon which is the icon that I&#39;m going to use so here this is just saying give me all of the normal props that the asterisk icon can use and that&#39;s because inside of here I&#39;m just going to return an asterisk icon and I&#39;m going to pass in all of those props and I&#39;m also going to pass in a class name and this is where I&#39;m going to Define my own custom class names so CN this is going to be text destructive it&#39;s going to be inline a size of three and I want to align this on the top finally I want to pass in what additional class names are passed into this function so all this is doing is rendering out a red Aster icon with the ability to customize further if needed so now I can put that icon into there and there we go that should be all I need I&#39;m just going to put it directly inside my form label I&#39;m also going to go back to my details form and add this in there as well so this description is optional so inside of here the name that&#39;s required and the URL here is required import that give it a save and now you can see we get this nice red asteris for those things that are required which is great now we can go back to the customization form and finish this out so underneath our label we&#39;re going to have our form control and inside this form control we&#39;re going to have a text area and this text area is going to be disable if we cannot customize our Banner so we have our can customize Banner if we can&#39;t it&#39;s going to be disabled we&#39;re going to have a class name here which is a Min h of 20 resize none and then finally all of my different field props just like that close off the text area and now you can see we have this text area shown up and it&#39;s disabled because I currently cannot edit this because of the particular tier that I&#39;m working with so we have our form control then we&#39;re going to do our form description and the form description here I&#39;m just going to copy over all this says is that the different data parameters that you can use so here it&#39;s saying that country coupon and discount are going to be replaced with their respective actual real world values so this is the left hand side of our entire thing when we&#39;re on a larger screen size now I want to work on the right hand side of our entire section which is going to be a div for all the rest of our inputs so let&#39;s give it a class name of grid which is going to be grid Columns of one on small screen sizes and a grid Columns of two on larger screen sizes with a gap of six between them we&#39;ll close that off and then inside here we&#39;re just going to put a bunch of different form Fields so I&#39;ll show you exactly what I&#39;m talking about this form field is for the background color we just need to make sure we import the input function and our form message function and that should be all we need I believe I imported the wrong input so it looks like yes I did let&#39;s make sure I import the correct one this time there we go that gets rid of all the errors and here all we&#39;re doing setting out the background color the label is background color and the input is this so here you can see we can customize the background color if we had permission now I&#39;m just going to copy down the rest of these that are really straightforward so here&#39;s two more that are super straightforward text color and font size again super straightforward inputs that require no additional stuff the next one is going to be slightly more complicated because it requires a new component that is this switch component right here so what I&#39;m going to do is go to Shad CN npx Shad CN at latest and we want to add the switch component just like that that should install the brand new Switch component for us which we can use there we go so let&#39;s import that component and all I need to do is make sure the checked is set to my field value and on check change is set to the field.on change then I finally gave it a display a block so it shows up below my label so if we go to customize here and I make sure that this is saved I need to refresh my page to get it to work there we go you can see now I have this sticky icon that I could actually toggle one way or the other now the last couple things that I need are again going to be super straightforward inputs that we&#39;ve done before so we have a B Banner container the only difference about this one is I have description telling people what this actually Associates with this is just the HTML container where the thing is stored by default it&#39;s the body and then finally we have our class prefects which again I have a small description telling people what this actually does now lastly at the very bottom of my form just like before I&#39;m going to be adding a button that lets me save this but only if I can customize the banner will I show this button so right now I&#39;m not showing the button now to test what this would look like if I could do customization what I&#39;m going to do is go back to my edit page here and instead of passing in this I&#39;m just going to pass in true so I&#39;m going to say or true so that means no matter what I can always customize my banner and now you can see I have the ability to fully customize every single thing inside of this which is great now the only thing that we really have left to do besides actually make the saving of the form work is to work on implementing what the banner is going to look like up here because I actually want to import this as a component called Banner that&#39;s going to show all the information that we want to show so I&#39;m going to create this component in my component folder banner. TSX export function Banner just like that now this Banner takes in a lot of props I&#39;m going to paste in what the props are going to be essentially we have a message that&#39;s the message I want to show in our case this is the message right here I then have a prop for if I can remove The Branding or not because based on what tier I sign up for I may or may not have a branding message showing up that says hey check out easy PPP this company that created this actual Banner that you see then I have mappings that allows me to associate these Dynamic values with the real values so what should coupon be what should discount be and what should country be and then finally I have this customization and Country obviously should be required then I have this customization section which is just all the different customization fields on what everything should look like now the first thing that I want to do is I want to get the prefix that I&#39;m going to use for my CSS so my prefix is just going to be my customizations do class prefix or it&#39;s going to be equal to an empty string then I want to get my message but I want to make sure it&#39;s mapped to the correct values so I can take my entire object. entries of my mappings so I&#39;m essentially converting this object into an array and then I can reduce this array into a real message so let&#39;s make this a little bit easier to see by minimizing our screen down so we look at just this particular section so in this I&#39;m going to have my mapped message and then I&#39;m going to have a key and a value that come for my mapping so what I want to do is I want to make sure I call this into a function and here I want to take my mapped message and all I want to do is I want to replace anything that has the star key or not star that anything that is wrapped in Brackets followed by whatever my key is so coupon wrapped in Brackets discount wrapped in Brackets country wrapped in Brackets and so on I want to replace that with whatever the real value is so I want to call replace on this and to make sure that this starts with my normal message I&#39;m going to put my normal message in here and I&#39;m going to replace any apostrophe inside of here so any apostrophe like that I&#39;m going to replace all of those with the HTML version of them the reason for this is because I&#39;m actually going to convert this entire component to a string and if I have these weird strings already in my message I want to make sure those are removed and showing with the HTML version instead it&#39;ll just make everything flow better also I might as well while I&#39;m here use this as a regular expression as well so I can use a regular expression with the G key right here to make sure that it&#39;s going to be for all of that and since I want to use Dynamic values I actually need to call new RX just like this I believe and pass it in the string version there we go and then I can close that off that should give me a new regular expression actually it&#39;s Rex XP there we go just like that and I believe I also have the ability to pass in any Flags I want which I want the global flag this allows me to put Dynamic values into there so this will do all my replacing for me so I&#39;m going to get a message that&#39;s going to replace coupon discounted country with the actual real world values then I can return my actual jsx and this is going to be a little different than a normal component cuz this is the exact component I&#39;m going to send down and render on other people&#39;s websites so I need to make sure all the styling and CSS is self-contained so to get started with here&#39;s the basic layout for what this is going to look like you&#39;ll notice all my class names are prefixed with this prefix and I have easy PPP container as the default value for the container same with here I have easy P message and the easy PPP branding all of that is styled just like this I&#39;ll make sure I get my inment variables imported from the client I also something that a lot of libraries don&#39;t do that provide overrides is I provide a override class that you can use that way your CSS Styles will always be more specific than my CSS Styles just to make overriding things so much easier now the reason that I mapped all these apostrophes to this actual Amper sand syntax is because I&#39;m using this dangerously inner set inner HTML to set the actual message as my HTML inside this span again that&#39;s to make sure that it&#39;s going to be working properly with all these apostrophes and so on they&#39;re going to render out properly as actual HTML I wouldn&#39;t normally have to do but since I&#39;m sending this down to other people&#39;s websites that&#39;s why I need this section then I have here if you cannot remove The Branding I have this section right here which is just a link directly back to my website and again I can&#39;t use an href or a link I&#39;m sorry from nextjs because again I&#39;m rendering this on other people&#39;s websites this needs to be as barebones as possible now the next thing I need to render out is all of the different styling code that I have and this is just how do I want to style this application so I&#39;m going to copy this over and explain it in depth to tell you what&#39;s going on but it&#39;s overall really basic CSS the very first thing I&#39;m doing for my container is I&#39;m reverting all the Styles this is to make sure that every style that I have is going to be default I don&#39;t have any weird stuff inheriting from their stylesheet then I&#39;m just making sure things are in the flex column Direction so it&#39;s stacked vertically I&#39;m making sure my background color font size are all being set by the particular user&#39;s customization the font family is inheriting add a little bit of padding if they set it as sticky the position is set to Sticky and it&#39;s set to the top section and the text is in the center now for The Branding this is just a little bit different I have my color inheriting font size inheriting and I&#39;m making this an inline block just so it shows up on a new line and then finally making it so it&#39;s underlined so I can easily see what the text looks like this essentially lets users know that this is an actual link and all of this is in a style tag again because I need to be able to import this into someone else&#39;s website that&#39;s why this component looks so funky but now I can go ahead and actually use this Banner right here so I&#39;m just going to paste in what the banner will look like and you can see here that the banner is taking in a few different things first of all I need to get all my form values so that&#39;s actually really easy to do I can say form values is equal to calling watch just like that on my form and that&#39;s going to get all the values from my form then I&#39;m going to set up a fake mapping so I&#39;m going to say the country&#39;s India coupons half off discounts 50 just some fake mapping so that we can see what this would actually look like and then finally I have my customizations and whether or not they can remove The Branding to show that branding section or not so I&#39;m going to give that a quick save give my banner a quick save and now if we scroll over here you can see exactly what the banner will look like on their website now even when I click on it brings me directly to to this homepage when I click on that link so you can see this link is right there because they are required to show branding now if I go ahead and I actually change whether or not they need to show branding or not so for example in the section where it says can remove branding if I set that to True you&#39;ll see that if I give it a quick refresh that branding has been removed so again this is all set up based on our permissions and again I&#39;m going to remove this permission for customization in a little bit but for now I&#39;m going to allow myself to customize so we can actually see if saving this information will work so now you can see the banner and when I change information it live updates which is exactly what we want so now let&#39;s go ahead and make it so we can save this information and then work on permissions so the very first thing that we need to do make this a lot bigger so we can work on it and wherever we are actually doing our product customization form in our onsubmit we obviously need to call some update product customization function there we go we&#39;re going need to pass it in our values. product ID actually that&#39;s coming from customization product ID and then our values so we know which product we&#39;re doing this on and where our specific values are and then again inside of our actions we need to create this action I&#39;m just going to paste it down because this is pretty much the same thing we&#39;ve done over and over again it&#39;s very straightforward you can see first we get the user then we make sure our data is correct and we check to see if they can do the customization based on those permissions for now I&#39;m going to comment this out because we want to be able to test to see if this works so I&#39;ll just say that this is going to be true all the time we&#39;ll come back and fix this once we deal with per missions then I&#39;m going to call this update product customization DB and if it was successful render out a message so all the way at the very top here let&#39;s make sure we import this function just like that and now we can go ahead and Implement that function so export async function that&#39;s going to be updating our product customizations just like that inside this function we&#39;re going to be passing it down the data as well as the product and user ID that we&#39;re going to be updating this information for then the next thing we need to do is we need to get our product if the product exists that means the user has permission to update it and in that particular scenario then we just want to call the really simple update code get our product customization pass it in all the data where the ID is set to the ID we passed in so this first line of code makes sure that the user that we&#39;re thinking about is the one that owns this product second line of code updates our actual database and then finally we just need to revalidate our cache so here we&#39;re just saying redate our product cache for this particular product and for this particular user so this code again relatively straightforward very similar to what we&#39;ve done all over our application and once we get all these different building blocks in place as you can see it becomes rather easy to implement and write all these different functions and as you can see all this code is working as well the last step is just to make sure it actually works inside of the form itself so let&#39;s go back to the form and we can import this particular function just like that from the action version there we go that is the action version We implemented then what I want to do inside of here is I want to get my data by awaiting that information and then I just want to render out a message to the screen using toast again so const toast equals use toast there we go make sure I spell that properly and now we can render a message onto the screen whether or not it was a success or a failure so let&#39;s come over to here let&#39;s go ahead and we&#39;re going to change the font size to .5 RM very very small click save you can see it says it updated we&#39;ll refresh our page go back to the customization and you can see that that font size stayed really small so we know that this is working we&#39;ll just leave it at default though for for most part it really doesn&#39;t matter so let&#39;s go back again to our customization and now work on making sure that our actual permissions are correct so right now wherever we have the value of or true we need to change that so here this should obviously not be or true so now again all of this is disabled because we don&#39;t have permission and same thing here if we try to save without permission it should give us an error so now we cannot customize this page at all and we also should probably show the people that they do not have permission to access all this customization with a nice little custom message so inside of our form underneath of our Banner if they cannot customize the banner well then we should probably show them a message telling them that so we&#39;re going to put a div here with a class name put it some margin on the top just to give it a little space and we&#39;ll create something called a no permission card and this is a nice little card that we can put anywhere we want to tell people they don&#39;t have permission in a really nice and easy way so let&#39;s go into our components we&#39;ll create a no permission card. TSX and this is a very straightforward card as you can see here all it does is take in some children and by default the children say you did not have permission to perform this action try upgrading your account to access this feature the title of the card says permission denied we&#39;re rendering out the children as the description and then in the footer we have a link that goes to the subscription page so that they can upgrade their account and if we just come in here and take a look at that that would look like if I make sure to import that card just like that and save you can see we get permission denied you do not have permission to perform this action try upgrading your account to access this feature also you notice how our Banner is sticking to the the top that is intentional because we have sticky set to true but we don&#39;t really want that inside of our form here so I&#39;m going just going to put this inside of a div and that means that it&#39;ll be stuck inside this div so now when I scroll you can see it doesn&#39;t actually stick to the top of the page because that&#39;s not really what we want Even though technically it is what we want we don&#39;t want it on this particular form now when I click upgrade account it&#39;ll bring me to the subscription page which we haven&#39;t worked on yet but right now we have pretty much everything related to products done and it may seem like it&#39;s taking a long time to get here and that we have a ton left which I mean we do have quite a bit left but but this is by far the bulkiest part of our entire project now while we&#39;re on the stage of permissions I want to focus on permissions for creating new projects as well because depending on what tier you&#39;re on you have the ability to create only a limited number of products so I&#39;m going to go back to my product new page because I actually need to implement authentication here so I&#39;m going to create a simple helper function called has permission this is a nice little component we can use that allows us to determine if a user has permission or not and if they do have permission we&#39;ll render the content inside otherwise we render out some form of fallback or just don&#39;t render anything at all so here we can say permission and this permission be can create product which is a permission we will need to create in just a second and this is going to render a fallback because we want it to render the fallback and we&#39;ll determine what that fallback text is if we want to be able to customize it so in our case I&#39;ll just copy over this fallback text and essentially it&#39;s just saying you have created the maximum number of products try upgrading your account to create more so now we need to both implement this can create product function and this has per per component the has permission component is going to be really easy so we can do that first has permission. TSX this component right here all it does is like I said takes in a permission a fallback whether or not we want to render it any fallback text and the children so the permission is a function that takes a user ID or a null and if you remember all the permissions we&#39;ve created so far that&#39;s the exact parameters they take it also is optionally able to render a fallback if you don&#39;t want to render the fallback it just returns null if you don&#39;t have permission and if you want to be able to change the back text that goes in that no permission card so that no permission card we already created handles all of this for us so really all this function does is get the user ID check to see if the user has permission if they do render the children if they don&#39;t render the fallback but if you don&#39;t want to render the fallback literally render nothing at all super straightforward function for the most part we&#39;ll go ahead we&#39;ll import that and now we can work on can create product so we need to go into our permissions right here and we need to create a brand new one async function can create product user ID string or null and this is going to be pretty much the same thing we have up here if the user ID is null return false then we want to get their subscription and this time it&#39;s going to be a little different because we have a max number of products so we need to get how many products they have as well so we can just say const product count equals await G product count just like that we can pass it in a user ID then we just need to create this function which again is in our database folder so we can create a function just going to pretty much copy this function that we have here this is just going to take in a user ID which is a string it&#39;s going to call get product count it&#39;s going to be on the products but this is going to be a user tag instead because we&#39;re going to have a user ID and then down here we pass in the user ID so there&#39;s our git product count function now we need to make sure we just create the internal version of that so function git product count internal it&#39;s going to take in a user ID which is a string and it&#39;s a very simple function all we do is get the counts this is going to return to us an array we&#39;re going to await calling DB Dot and we want to do a query so we&#39;re going to select actually and we want to select specifically the product count and that&#39;s just calling the count function directly from drizzle so this allows us to count up all the different products in our database we can get this from the product table so we&#39;re getting all of the ones from our product table and we specifically want to get them where a certain criteria is true and that criteria that we&#39;re waiting for is going to be an equal criteria and we want to check to see where our product table. clerk user ID is equal to our user ID make sure this is an asynchronous function and that gives us an array of different counts and we just want to return the first one from our array so counts of zero we want to get the product count otherwise we&#39;re just going to return zero if we don&#39;t get something from the array cuz that means they have no products at all so that&#39;s all it takes to create this particular permission that&#39;s relatively easy we can go back to our new page here we can import this function just like that and we can finish implementing this function because now we need to make sure we get this and we need to make sure that their product count is less than the amount that are allowed and that means that they can still create new products so now whenever we try to create a new product if they already have the maximum number of products it&#39;ll give us a nice warning so here new product you can see canate product is not defined we looks like we need to save the file we forgot to click save so here give that a save now you can see I&#39;m trying to create a product but I already have the maximum number which is one so I get this nice permission denied message showing up on the screen I also need to make sure in my action for creating a product that I also make sure I check to see if they can create a product before I go ahead and do it so we&#39;ll scroll all the way up to the top where I have create product and at the very top here I&#39;m just going to check can they create the product for this particular user ID and if they cannot create the product then I&#39;m just going to throw down an error to the user so again a really easy way to check and make sure that they able to create it before we Implement anything in our database now the final thing for products that we really need to do is to implement the products page we haven&#39;t implemented this page yet but luckily this page is dead simple page. TSX I&#39;ll paste in the code for it that&#39;s just because we&#39;ve already written this page essentially entirely this page all it&#39;s doing is getting all of the different products for a user ID make sure I import that properly looks like it&#39;s still throwing an error I believe that&#39;s because we need to make sure that this is optional we don&#39;t want to have to pass down a limit that should fix that error there we go so now all I&#39;m doing is I&#39;m getting my user id redirecting if they&#39;re not null or if they are null sorry then I&#39;m getting all my products if we don&#39;t have any show the no product screen otherwise show my product Grid it&#39;s literally the exact same code as our dashboard if we go to our dashboard and our products you&#39;ll notice they&#39;re almost identical minus the fact you can link to the product page from the dashboard so now we have everything done with our products actually for real this time we can move on to dealing with our subscriptions because that&#39;ll lead perfectly into dealing with all of our analytics so let&#39;s go ahead and create our subscription page we come over to our Pages we&#39;ll just minimize all these so we can kind of get started from complete scratch since we&#39;re kind of on a whole new section of the application now in the dashboard we&#39;ll create a folder called subscription and inside of here page. TSX export function subscription page and make sure that this is a default function so there we go we at least have something we can return on our subscription page so now we go to that page at least we have something to render now on this page here what we need to do is first get all of our user information so user ID that&#39;s equal to off and we need to get the redirect to sign in as well and of course if our user ID is equal to null then we&#39;ll redirect them to the sign in just like that now the next thing we need to do is to figure out what tier the user is currently on so we&#39;ve already created a function for this this is the really nice thing about using those DB functions cuz now I can just get my user subscription tier boom passed my user ID and now it&#39;s just going to work make this an async function you can see everything just works same thing here I want to get how many products I&#39;ve created so I can say get product count and that&#39;s a weit get product count boom we&#39;ve already created this it&#39;s that easy so now we have the number of products that we&#39;ve created I also need to get the number of times I&#39;ve viewed the pricing page because on this subscription page I&#39;m going to show you how many views you have left how many products you have left and so on so I&#39;m going to say get pricing View count is a weit get product view count we&#39;re going to pass in our user ID and also we need to pass in where we want to count this from I&#39;m going to be counting from the start of the month with whatever the current date is now this start of month I need to make sure I get from date FNS so npm I date FNS this is just a really handy library for dealing with dates once that&#39;s installed really quickly we can go ahead and actually import this function we just need a manually import for now import start of month from date FNS there we go so now we just need to implement this git product view count which is a relatively simple function so we&#39;re going to go over to our server inside of our database we need to now get one for product views. TS export function get product view count and we also need to get the internal version I&#39;ll paste down what the internal version looks like it&#39;s a relatively simple function and I&#39;ll explain obviously in- depth exactly what each line of code is doing but it really doesn&#39;t make sense to have me type out each line individually so let me just get all my imports in real quick get that import and then finally we need to do this import and greater than input so all this function is doing is taking in a user ID and a start date and what I&#39;m doing is I&#39;m querying on my product view table I want to just count all my pricing view counts so just get a count of everything then what I want do is I want to join this on my product table where my product ID is equal to the View&#39;s product ID so I only want to be able to get the products that the user has actually done so here I&#39;m checking the product table for the user ID and I&#39;m checking to make sure it&#39;s greater than the start dat so really what this code is doing is it&#39;s getting all the count of how many rows are in my view table that are associated with the products for my user and or after whatever the given time that I pass into this function is and then I just need to set up everything with my caching so here I can call all that caching related code and just make sure I import everything that I need so I get my user tag here and of course all my props are going to be the same props from up here get the cache tags just like that so this is going to be caching for a particular user because again there&#39;s no individual ID it&#39;s just a user ID since I&#39;m checking all my product views for this particular user and now we can come back into here and we have our count function implemented it&#39;s very similar to our product count we&#39;re just making sure we have an extra joint in there and that&#39;s about the only step now we pretty much have all the information we need to implement this function so the first thing I want to do is render out a top section here that&#39;s just going to be the title for our page H1 it&#39;s going to have a class name too to make this a little bit larger margin bottom of six text is going to be 3XL font is semi bold and then in here we can just put the text your subscription and now you can see we get that text showing up on our page the next thing we can focus on is going to be for all of our different content at the very top of our page which is going to be all the content for how much we&#39;ve used in our subscription so we&#39;re going to have a div here and it&#39;s going to have a class name of flex Flex column Gap 8 and margin bottom of eight and then inside of this div we&#39;re going to have another div because this is going to be our column based layout essentially we&#39;re going to have two cards that represent how many views we have and how many products we have and then another card for managing our subscription if we have one so here this is going to be for containing our two separate side by-side cards so we&#39;re going to have a grid grid Columns of one or on a larger screen size obviously the columns are going to be set to two and a gap of eight then inside of here we can render out each one of our individual cards so let&#39;s import our card we&#39;re going to get our card header from here our card title in our case I&#39;m going to make the text a little bit larger just like that and this is our monthly usage so this is just how many views we&#39;ve essentially had in the month then we&#39;re going to have our card description and inside of here we&#39;re going to use that format compact number function we created earlier to take how many views we&#39;ve actually already had and then we want to compare that to the exact same formatted of our compact numbers of our maximum number of views so this is the maximum number of visits for our pricing page and this will say pricing page visits this month give that a quick save you can see here&#39;s our monthly usage we have zero total pricing page visits this month because we aren&#39;t tracking any of that information yet next we&#39;re going to do our card content and inside of here I want to render out a progress bar which is something that we can easily get from Shaden so let&#39;s just import the progress component from Shad CN it&#39;s a relatively simple and straightforward component shouldn&#39;t take too long to install and now we can import that progress component and inside of here we can give it a value and our value is just going to be our pricing view count divided by our tier. maximum number of visits we need multiply that by 100 to convert it to a number between 1 and 100 now if we give that a save you can see we have that bar showing up right there now the formatting looks a little bit off so my guess is I imported my card content from the the wrong location looks like that&#39;s the right location but my progress that&#39;s also the right location so it does actually look like everything&#39;s being imported from the right location let me just make sure uh my card content should be outside my header that should fix my styling and there we go we now have our progress bar showing up now we&#39;re going to make what&#39;s arguably an identical card for our number of products so same text large we&#39;re going to have the exact same product count and number of products and the same thing for our progress bar and if we say that you can see we get that showing up now I&#39;m going to slightly modify our progress bar instead of using a background primary I&#39;m going to come in here with a background of accent instead so let&#39;s just make sure I spell accent properly give that a quick save and now you can see we have a blue background instead of the black background which looks better for our particular styling and on a larger screen size you can see that these two elements will show up side by side but actually it doesn&#39;t look like that&#39;s quite working so there&#39;s clearly something going on inside of my grid here you can see grid columns one on medium it should be grid calls 2 and now when we expand our screen size you can see they are side by side so that is working as we expect now after this we need to have another card for managing our subscription and this is only going to be a card that exists if we already have a subscription we&#39;re paying for because this is for managing our subscription inside of stripe so if we have a free subscription so far there&#39;s nothing in stripe if that makes sense so if our tier is not equal to subscription tiers whoops subscription tiers. free then we don&#39;t want to render this or we do want to render this I&#39;m sorry so if our subscription is not free then we&#39;re going to render out a brand new card let me make sure I get rid of the Subscribe for from here that shouldn&#39;t be there there we go card header inside of there we know our card title and I&#39;m just going to copy down what the content in the title and description is cu it&#39;s just plain text you&#39;re currently on the whatever the tier is if you&#39;d like to upgrade cancel or change your payment method use the button below and then we need to actually put a button so we&#39;ll say card content just like that inside of here we&#39;re going to have a very basic form with an action and the action is going to be for creating a customer portal session this is going to be dealing specifically with stripe and this is just going to create a link and redirect the user to that link so what we&#39;re going to do is just put a simple button inside of here our variant is going to be accent we&#39;re going to have a class name on here so we&#39;re going to say text large rounded large and then our size is also going to be large this is just going to be an overall relatively large button that says manage subscription and then let&#39;s go ahead close off that button just like that and of course we don&#39;t have this action yet so let&#39;s just remove that so we can see what our code looks like and you can see right now we are on the free subscription if we just make this say equal free subscription you can see you&#39;re currently on the free plan if you like to upgrade blah blah blah do this and again make sure our card content is outside of our header to make sure our styling looks right there we go so now we can add in that action that we removed so action equals and this is going to be create customer portal session we&#39;ll go ahead and Implement that in just a second but obviously we&#39;re going to get an error because it doesn&#39;t exist quite yet so I&#39;m just going to move on and we&#39;ll come back and create this function in a second because we&#39;re going to create some other functions with stripe that are going to do similar things so the next thing I want to work on is dealing with all of my different pricing cards because I&#39;m going to render out each individual pricing card this codee&#39;s almost identical to what we had before for rendering our pricing cards and I want to render each individual pricing card out and I want to show them with a button that says like upgrade downgrade swap whatever it is so let&#39;s go ahead and get all of our pricing code functioned now I&#39;m going to copy this over this is about 90% identical to the pricing card that we&#39;ve already created but I&#39;ll go over the major differences once I get all the different things imported that we need so get our tier names imported from here and we can make sure that these functions will create in just a second and then finally we need to implement our card footer and react node from here and of course get the check icon and this CN class right there so this feature section identical nothing about this changes it&#39;s exactly the same as what we had before all the stuff in our footer identical all the stuff in our header idental the one major difference between these two versions is in the card content we have a giant form that instead of bringing us to the sign up button brings us to a button that is either going to allow us to cancel by deleting our session or by creating a brand new session which allows us to check out and sign up for a subscription for the very first time so what we can do is we can come in here I&#39;m going to comment out these actions just because we don&#39;t have one yet so I&#39;m just going to put undefined into here and same thing up here for our action I&#39;ll put undefined just so we can see what this looks like like now if we save you can see down here I have my four pricing cards you&#39;ll notice they look identical the only difference being is that these buttons for the current one says current and is gray out and the other ones have the ability to swap and they&#39;ll submit a form for us when we click on them right now the forms do nothing so let&#39;s bring in those functions and go ahead and actually work on creating those different functions for stripe implementations also what we need to make sure we do is scroll all the way to the very top set this to not equal to free and now we can go into our server folder we can create a brand new file called stripe for managing all our different stripe related things so we have an async function called create checkout session function just like that and we don&#39;t even need to pass anything to this except for the tier that we&#39;re going to be creating this for so we&#39;re going to create a tier and this is only for our paid tier names so I&#39;m going to say paid tier names and I&#39;m going to actually create that type inside of our data so go into our data subscription tiers we&#39;re going to export a type which is paid tier names which is just equal to tier tier names but we want to exclude the free tier there we go so now paid tier names is basic standard or premium that&#39;s exactly what we want make sure we import this and there we go we&#39;re importing one of the tiers that we want now the next thing we need to do is to get our user and we actually need the full user information because we need to be able to get certain things like the stripe custom ID and so on so this is going to be called await current user and that is actually coming from Clerk and allows us to get our current user and if our user is equal to null then we can just return that there was an error so we&#39;ll say error true next thing is we can get our subscription so subscription is equal to get user subscription and we&#39;ll pass in our users ID again since we already created all these functions it&#39;s super easier for us to just Implement them and use them without having to worry about anything else so we&#39;ll await that function now down below we can say if our subscription is equal to null again we have an error so return error true otherwise we can finally move on to this next section so this is where we&#39;re going to Branch a little bit so if we don&#39;t have a subscription yet then we want to be able to create a brand new subscription so if our subscription oops subscription. stripe customer ID if this is equal to null well then we want to create a brand new checkout session otherwise we&#39;re going to piggyback on some of the features built into stripe so this is going to give us a URL and we&#39;re going to call get checkout session we&#39;re going to pass it in the tier the subscription and the user that we&#39;re creating this for so let&#39;s create that function function G checkout session and we&#39;re going to pass it in all of that information and I&#39;m just going to copy over the typing for that information because the paid tier is going to be one of our tiers here we&#39;re going to have our subscription and the only thing we care about is a stripe customer ID and the stripe subscription ID and then our user just gets the user type from clerk now to to use this function we need to First figure out what customer details we need for our user so our customer details is equal to and this depends on if our subscription has information for our particular user and actually we don&#39;t even need to do this because we already know our stripe customer ID is null so we don&#39;t even need to pass in our subscription information we only really need the user and for our customer details this is going to be rather straightforward we want to take our customer and we want to set the email specifically and that&#39;s just user. primary email address and we want to get the email address property from that so this is just going to get whatever the user&#39;s email address is and that&#39;s going to be our customer details so what we can do next is we can say that we&#39;re going to have a session and that&#39;s going to be called await calling the stripe function and this means that we now need to import stripe into our application so we can say npmi stripe just like that that&#39;s going to import stripe and then all the way up here we can say import Stripe from stripe we also need to make sure that we move this stripe folder or file into our actions folder cuz technically these are going to be actions that we can call so let&#39;s make sure we call use server at the top here because these are actions there we go we now have access to stripe and we can just say const our small stripe is going to be equal to creating a brand new stripe instance using our server environment variables which we need to import server environment from and that&#39;s going to be at slash data SL environment server there we go and we want to get essentially our stripe secret key there we go and let me make sure I spell all of this properly and now we&#39;re getting an error because we don&#39;t have stripe secret key to find on here so stripe secret key z. string and let&#39;s actually put that into our actual environment variables so to do that we need to go ahead and log into stripe and once you&#39;re inside of stripe we essentially need to find the section for our API Keys a lot of times you can go to settings and click on developers and we can see here API Keys now inside of this section just zoom it in a little bit so it&#39;s easier to see we have the publishable key and the secret key we&#39;re just going to be getting the secret key cuz we&#39;re not even doing anything on the client everything we&#39;re doing is on the server so let&#39;s just copy that we&#39;re going to minimize all this down go to our EnV file section we&#39;re going to create a new section for stripe we have our stripe secret key and we&#39;re going to set it equal to that secret key that we just added in I&#39;m also going to make sure I copy this over into the EnV example section and add a section here for stripe as well so let&#39;s save all that information save this and now hopefully with all that done we come back over here and refresh obviously we&#39;re still getting errors but at least this section is fixed and now we can actually access the stripe API to do things so here we want to create a basic checkout session so we&#39;re going to say we want to create a checkout session just like that and we want to pass along all the information we need so I&#39;m just going to take this customer email paste it into here get rid of this customer details up there the next thing we need to do is pass along all the data for our subscription so our subscription data we specifically just want to have some metadata clerk user ID is user. ID this way we can link together our subscription with our clerk user the next thing we need to do is to specify any line items that we have this is the thing that someone is going to be buying this is going to have a price section and it&#39;s going to have a quantity which in our case is always going to be one because we&#39;re just buying one single subscription now for the price this is actually something that we&#39;re going to be getting and setting inside of stripe so inside of stripe I&#39;ll make this quite a bit larger so you can see we have this product catalog section where we can create different products so for example if this basic product right here all I did was create a product I&#39;ll show you what it looks like you can just click add product all you need to do is type in the name of your product optionally give it a description if you want determine the amount that your product is going to be and whether or not it&#39;s going to be recurring in our case we want it to be recurring and be monthly and there we go that&#39;s how you create a product you click add and that&#39;ll create the brand new product for us we have a premium standard and basic product already created and what we can do is we can go inside of here and we just need to be able to get the product IDs so here we have our product IDs we actually need the pricing ID so we can click on our price and up here we get the pricing ID and that is what we&#39;re essentially going to put into here we&#39;re going to put each one of these pricing IDs now I want to make sure that these are private variables so inside of our EnV we&#39;re going to have our stripe basic plan price ID and set it equal to that and we&#39;re going to get this for each of them so instead of making you watch me type these out I&#39;m just going to copy each of those plans in and then I&#39;m going to go over to our example and again same thing going to paste those down and I&#39;m going to delete them because we don&#39;t want them to be stored in there so now we have all of our different plan IDs I can now add these into our environment variables so we&#39;re going to have our different plans again let make sure I get this hooked up right z. string comma afterwards z. string and there we go now we have those inside of our EnV variables now we can actually use them which is really great because if we go back to our data folder that&#39;s where we set up all of our subscription tiers and I can add in the stripe price ID just like this so stripe price ID is going to be EnV I want to get my server ones and I want to get the basic plan so I&#39;m going to take this and I&#39;m going to move it down to here now this one doesn&#39;t have a stripe plan ID so we&#39;ll say stripe price ID is going to be undefined or null it just doesn&#39;t have one so we&#39;re going to specify it as null then we&#39;ll move this down to both of these this one is going to be the premium version and then this one right here is standard so now we at least have all of our IDs associated with each one of our different projects or our products I&#39;m sorry our tiers actually and now we can just say tier Dot and we can get the actual pricing plan for it so this is based on our tier plan names so that means I need to take my subscription whoops subscription tiers I need to get the one for the specific tier and I want to get that stripe price ID just like that so this is is going to be an ID of a stripe price and that means it&#39;s going to be perfectly linked with our stripe database so we specified what the customer email is we specified how to link this to our customer we specified what they&#39;re purchasing now we need to specify that this is going to be a subscription so stripe knows this is a monthly payment and then we need to have a success URL which is where we redirect the user to and this is coming from our client EnV so all the way up here I&#39;m going to copy this down I&#39;m going to get our client environment variables from the client version of this file so our Cent EnV comes with a next public server URL and we just want to redirect them back to the page they were just on so the subscription page and we want to do the exact same thing for a cancel so the cancel URL bringing them back to the exact same place then all we want to do is down here return our session. URL back to the user so up here we now have that URL which could be null so if the URL is equal to null then we just return an error otherwise we&#39;re going to redirect the user to that URL and this is going to redirect them to stripe where they can enter their payment information and so on now this is something we&#39;re going to worry about implementing it in just a little bit so we&#39;re going to come back here now to make sure that everything is going to be working we also need to implement the other two functions so we have an export async function and this one is going to be a create cancel session just like that for now I&#39;m just going to make it do absolutely nothing and then an async function called create customer portal session again I&#39;m going to make it do nothing these are just the functions that we created on this page so now we can import all of these different functions even the ones that don&#39;t do anything yet so we can at least see if this is working it looks like we&#39;ve gotten rid of all of our errors we come back over here everything is rendering and hopefully if I click on one of these buttons it&#39;s going to bring me to the page where I can actually purchase this product so I can click swap for example and now you can see it&#39;s brought me to this particular page where I can enter in my credit card information and purchase this particular product and if I were to go back for example you can see it brings me back exactly to this page now before we go ahead and actually test this implementation we first need to deal with web hooks inside a stripe so I&#39;m just going to search here for web hook you can see here we have the web hooks right there and this allows me to actually deal with creating web hooks so let&#39;s actually Zoom this out a little bit more so it&#39;s easier to see I will again go to the settings actually the developer button is right there you can see we can click on web Hooks and I get a bunch of information inside of here we&#39;ll Zoom it in a little more so it&#39;s easier to see you can see we have create local listener and create an endpoint I&#39;m just going to do local because that&#39;s how we&#39;re going to be testing first I need to install the stripe SDK and log in and then I can call stripe listen and forward it to whatever my particular URL is and finally I can trigger that particular endpoint and then from this exact page I can see what all the things are being sent along I can go to this events Tab and see all the events that are being sent along with everything for example I had a billion portal session created because of the things that I&#39;ve done so far so I&#39;m going to go ahead and I&#39;m going to come into my web Hooks and start implementing this web Hook from stripe It&#39;s relatively simple to actually do this implementation so to get started with implementing this we first need to create the actual location in our API we&#39;ll create a folder called stripe and inside of here we&#39;ll create our own routts file and inside this route. TS file we just need to get started with stripe now dealing with web Hooks and stripe is relatively easy we&#39;re going to export an async function called post that&#39;s going to take in our request whoops request and this is a next request and then inside of here I want to get my event which is as simple as calling a wait on the stripe and of course we need to get stripe so we can say con stripe equals new stripe make sure we import that and it&#39;s going to be getting my environment variable for my stripe secret key there we go so we&#39;re going to give be getting a stripe and I want to deal with web Hooks and I want to be to construct an event so here we go inside of here I want to get the body for my text so request. text is going to get all the text from whatever sent to me by stripe I then need to get the headers from stripe so get the particular header which is my stripe signature just like that and I&#39;ll say that this is a string because it should come back as a string and then I need to get my stripe web hook secret now to be able to get this stripe web hook secret we need to First Implement that into our environment variables so here we&#39;re going to say stripe web hook secret is a string in our environment variables in our stripe section we need to add in our stripe web hook secret and we need to do do the exact same thing on our example version as well now to be able to get that we just need to create a local listener so I&#39;m just going to copy this particular code to get the local listener go into my package Json and create a simple script for setting this up so here we&#39;ll just say stripe and I&#39;ll just call this web hooks just like that and this is going to call stripe listen and I want to forward to Local Host 3000 API web hooks SL stripe and that that&#39;s going to do is forward every single stripe API web hook to this particular URL when I call that so what I can do is I can say npm run stripe web Hooks and if I give that a quick second to run you can see that it is going to give me a brand new secret key that I can use and it&#39;s going to say hey you know what everything is up and running so now we can go ahead into our route or not into our route into our environment variable paste that key in and now we have a secret key that we can use for our web hooks as well so now if we go back to that web hook that we were implementing right here we can set okay now we have an event and we can switch on the particular event. type there we go so event. type in the particular case that we have a customer. subscription deleted I want to do something I then want to do the exact same thing in the case that I have a customer. subscription and I want to do when I have an update or not an update yeah an update that&#39;ll work make sure I put the colon at the end of these there we go and I&#39;m going to copy this one more time for what happens when we have a created ad as well so I think it&#39;s just create nope created just like that and then finally at the very bottom I want to return a new response which is null and has a status of 200 just so stripe knows that this successfully worked so let&#39;s get started with the created all I can do is say await handle create pass in my event. dat. object and then I can put a break statement and I can create a function called handle create which takes in my subscription which is a stripe. subscription just like that so it&#39;s giving me all of my subscription data from stripe now I can copy this and paste this down a couple times but this one&#39;s going to be for handle delete and this one&#39;s going to be for handle update there we go and I can create essentially the exact same function for handle delete and handle update and they&#39;re all going to do different things but they&#39;re going to be relatively similar between all of them so inside of handle create the very first thing I want to do is get my tier for the user so I say tier is equal to get tier by Price ID and I can pass in my subscription. items. dat this is that list of line items that we created so if we look at this create checkout session I&#39;m sorry not this one it&#39;s this one right here these line items that&#39;s this list that&#39;s giving it back to us so we&#39;re going to get the very first item from there and I want to get the price. ID so now I can use this function that I&#39;m about to create to get a tier based on that price ID so back into here I&#39;ll create a function make sure I export this this is going to take in a price ID which is a string and it&#39;s actually a stripe price ID there we go make sure I actually spell all this properly and then I can just return subscription tiers and actually it&#39;ll be easier if I just paste this in there I just want to get the values from that and get it based on my stripe price ID so essentially I&#39;m just looping through each of my subscription tiers and returning whichever one has the right price ID that&#39;s going to return to me single one of my tiers now what I can do is I can go back to here and this will get me a particular tier which will give me all the information I need to be able to create this in my user the next thing I need to do is figure out which user this is associated with so my clerk user ID is going to be equal to subscription. metadata that&#39;s why I set that metadata and I want to get the clerk user ID now obviously if my clerk user ID is equal to null or my tier is equal to null then something bad happened and I need to throw an error so that way I know for in fact there&#39;s a problem so I&#39;m going to return a new response with null and status of 500 so now we have an error please somebody solve that the next thing I want to do is get my customer information from stripe so I can say that&#39;s equal to subscription. customer make sure I spell that properly there we go that&#39;s going to give me all of my customer information namely this is a customer ID that it&#39;s going to get for me or it could be a customer object so I want to get the customer ID from that so I&#39;ll say customer ID is equal to to and I want to check the type of my customer if it&#39;s equal to a string there we go then I know that I can just return whatever this is because it&#39;s an ID but if it&#39;s not equal to a string well then I want to get the ID property from my customer by saying customer. ID so this may or may not be a string and depending on what we do we want to make sure we get the right value then finally I can actually update my user subscription so I&#39;ll call a function called update user subscription that&#39;s going to be accessing my database I essentially just want to pass along a bunch of information into here so I&#39;m going to go and create this function now so we&#39;ll come all the way down into our section for our database which is inside of our server and our database we got our subscription section and here export function update subscription just like that and it&#39;s actually called update user subscription now inside of here I need to obviously get all my data and so on but let&#39;s go ahead and write out our database query so let&#39;s make sure this is asynchronous and we want to do a db. update and we want to update the user subscription table and we want to set our data so we can get that data in safely from here which is just a partial for my type of user subscription table. infer insert that&#39;s pretty much the same as all of our other update functions then I want to do it where specific things are true and unfortunately I can&#39;t just do a generic where wear based on like user ID or stripe customer ID because depending on if we&#39;re doing a create an update or delete we&#39;re going to get slightly different information back so I&#39;m actually going to take my wear in directly from my update function so up here I&#39;m going to pass in a wear which is just going to be SQL and this SQL is just a type that comes directly from drizzle so it&#39;s saying just any amount of SQL that I&#39;m going to write is coming in as my wear Clause then what I want to do is I want to make sure I return specifically the ID which is the user subscription table. ID and I want to get the user ID which is my user subscription table table clerk user ID that way I can use that to revalidate my cache so I can say updated subscription is equal to waiting for that and then if my updated subscription is not equal to null make sure I spell that properly there we go then I can revalidate my DB cache where the tag is the cach whoops cach tag. subscription I want to get it for user ID which is my updated subscription again didn&#39;t spell that properly and then finally my ID is my updated subscription. ID so just revalidating my cash for all that information so I just now need to pass along aware as well as all my data directly from this route right here so let&#39;s make sure we import that just fine here for my wear Clause it&#39;s just going to say I want to check equal user subscription table dot in our case I have have a clerk user ID so I&#39;m going to check for my clerk user ID and then we can pass along all the different data so if we look here the data we need is our clerk user ID well that&#39;s pretty easy but we don&#39;t really need to add that in there if we&#39;re doing an update so we can do just next step of thing which is our stripe customer ID which is our customer ID we also need to get the tier that they&#39;re upgrading to which is just tier. name we need to get the stripe subscription ID which is our subscription. ID and then we need to get the stripe subscription item id which again is coming from our subscription. items we want to get the first element from our data array because we&#39;re only ever passing one and we get the ID for that so now if we make it this an asynchronous function and then we come into here we can just return a waiting for this and now there we go we automatically have the ability to handle the creation of different user subscriptions so whenever someone signs up we update their subscription to that next tier level so hopefully this all should be working I&#39;m already listening for my web hooks so let&#39;s go ahead and just test that and see if everything works properly so I&#39;m going to come in here I&#39;m going to upgrade to the basic plan I&#39;ll make this a little bit larger Zoom this in and I can come in here just enter a bunch of credit card information enter a name enter a random zip code none of this information actually matters and we&#39;ll click subscribe and hopefully everything will work successfully it&#39;ll redirect us to the last page we were on and we should see it actually updates their subscription and look at that we&#39;re now on the basic plan you can see we have one of five products we have a monthly usage of 10,000 now so now we have the ability to actually spap between different plans and we have this manage subscription button right now it doesn&#39;t work but you can see it showing up so we at least have handle create completely finished now while we&#39;re here I might as well do the update function as well so for the update function it&#39;s going to have some similarities to this function for example we need to be able to get the tier so just paste that in there we&#39;re going to get the tier based on that ID I want to be able to get my customer information as well so we&#39;ll copy that down but we don&#39;t have the clerk user ID cuz we don&#39;t have any metadata that we can pull from this subscription so instead what I&#39;m going to do I&#39;m going to first just check if my here is equal to null then I&#39;m going to return a new response that&#39;s going to be a status of 500 again just throwing down an error to the user and then we just want to call this update function again so let&#39;s just do that we&#39;re going to call update but this time we don&#39;t have a clerk user ID but I do have a stripe user ID so I can say stripe customer ID is customer ID and in that case if we&#39;re updating our subscription the subscription ID should stay the same the item id should stay the same the customer ID should stay the same the only only thing changing is the tier for what we&#39;re updating so that&#39;s the only thing I&#39;m going to pass along to this particular function now finally we need to handle delete and again I want to get my customer information so I can get my customer information from here and I can just essentially call the exact same function but this time I&#39;m going to be updating the tier specifically to the free tier so I can say subscription whoops a subscription tiers there we go free. name and I also want to make sure that I take the stripe subscription ID and remove that so let&#39;s say stripe subscription ID is equal to null and our stripe subscription Item ID is equal to null because we&#39;ve removed this subscription from the user there we go now we can keep the stripe customer ID because they&#39;re still associated with that particular user but we can get rid of all the other stuff and downgrade them back down to the free tier so we at least have handled all the different scenarios that stripe can throw at us with the different web hooks that we&#39;re dealing with so now let&#39;s go back to stripe and implement the rest of our different functions here so we have this create customer portal session as well this one&#39;s actually relatively easy we first need to get our user ID which equals await actually I&#39;m sorry we don&#39;t need to wait we just need to get our off just like that then the next thing is obviously if our user ID equals null to return an error just like that and then we need to get our subscription which is just get user subscription again something we&#39;ve already created in the past and then if our subscription whoops sub cription do stripe customer ID obviously I need to await this there we go if the stripe custom ID equals null then we have another error so we can return error true and that&#39;s because to view this portal you need to view it as a customer so now let&#39;s get our portal session which is just equal to await make sure I spell that properly and we want to get stripe. billing this time and we want to get the billing portal specifically and we want to create a session for that so we can create it for our subscription. customer ID and we can get a return URL which is just going to be the exact same as our success URL down here so I&#39;m just going to find where I pasted that and we&#39;re going to copy that exact code so up here for our return URL we&#39;re just going to paste that in and then finally we&#39;re going to return or I&#39;m sorry redirect to our portal session. URL just like that so now if they click the manage session button or manage subscription button it&#39;ll bring them to their portal so let&#39;s refresh and see if that works manage subscription and you can see it&#39;s redirected me right here to this ability to actually manage everything related to my subscription now you may notice that yours doesn&#39;t quite work right away so come over here and search for customer portal or actually it may be billion portal there we go billion customer portal you need to search for this particular page right here and you just need to go through and you need to set up all the information for how your page works and you need to make sure that it&#39;s activated once that&#39;s done you should be able to actually see and use this inside your application and this allows them to update their plan and so on so for example I can update my plan to the standard plan click continue it&#39;s going to ask me to confirm I click confirm now after a quick second after the payment goes through we should see when we go back to this particular page the user is now on the standard plan and that&#39;s because the web Hook from Strike sent over to my application and said hey they went ahead and they updated their plan and it went over and updated me to this particular standard plan now now if I were to swap back to this plan that button currently doesn&#39;t work so we need to make sure we Implement that next this is luckily not too terribly difficult to do where we have our create checkout session you can see we have this else section we still need to implement for what happens when they already have a subscription and we want to update it in that case we want to call the git subscription upgrade session function which we&#39;re going to create we&#39;re going to pass in our tier and we&#39;re going to pass in our subscription and we&#39;ll say const URL is equal to that and then we will just redirect to the URL down here and there we go that&#39;s all we need to do inside of this function so let&#39;s go ahead and create an async function called get subscription update session or upgrade session it&#39;s going to take in a tier which is a paid tier name and then it&#39;s going to take in our subscription and the subscription is going to have our stripe customer ID which is a string or null and it&#39;s also going to contain our subscription and item id which we all need all of this information to make all of this work so the very first thing I can do is just check if any of these do not exist then I want to just essentially throw a new error by returning a new response and this response is going to be null status 500 then we can just go ahead and create a brand new session just like we did all the way up here we essentially want to create the same thing that we did here so I&#39;m going to paste this down we want a billion portal session we want to create it for this particular customer we want the exact same return URL but this time we want to specify where we want them to go by giving them a type of data so this one is going to be an update confirmation then what we can do is we can say for that update confirm what we want to do is pass along what the subscription is that is just our subscription. ID so we want to get the subscription ID then what we need to do is pass along all the different items that we&#39;re going to be updating so the ID is our subscription and we want to get the item id we want to get the price that we are upgrading them to which is coming from our subscription tiers for our particular tier and we want to get the stripe price ID and then finally the quantity which in our case is always going to be one so all this complicated bit of code does let me just make sure at the bottom we return our portal. URL all this complicated bit of code does is essentially say hey bring them to that exact same billion portal but make sure you bring them exactly to the page that updates their subscription to the brand new subscription that they selected that&#39;s all that you need to do in this section so now we can see here that we need to make sure we await this function and everything should work if we give that a quick save it&#39;s still saying this could be a string or a response I should probably just make sure here I just throw a new error instead there we go that just cleans that up makes it a little bit easier so now if I come in here and I want to swap to for example the basic plan if I click on Swap you can see it&#39;s loading it&#39;s loading it&#39;s loading and now I have the ability to confirm my update to downgrade to the basic plan the last thing I need to handle is what happens when I want to do a delete so let&#39;s just come all the way up here for the delete just like in all the other ones I need to get the particular subscription that I&#39;m dealing with and in this particular case I need to figure out if I have a customer ID and if I have a subscription ID otherwise I want to return a new response there we go and this is going to be null with a status of 500 just to say hey there was some type of error these things are required to be able to do this cancellation because if you don&#39;t have a subscription you can&#39;t cancel it now to get our session it&#39;s going to be very similar to what we did down here I&#39;m actually going to copy this entire thing bring it all the way up here but instead of returning I&#39;m going to redirect to the portal session. URL and this time I just want to change our type so our type here is going to be for the subscription cancel and this is going to be subscription cancel and we just need to put different information inside here it&#39;s actually very simple we just need to specify what subscription we&#39;re canceling which is our subscription. stripe subscription ID there we go make sure I put the final parentheses there and this allows me to create a URL that goes directly towards canceling so now hopefully if I click to swap to free that is essentially canceling my subscription and we should see it redirects me to the page that says are you sure you want to cancel your plan boom there we go I and cancel right there if I want to obviously I&#39;m not going to do that because I want to still maintain my subscription now the final thing we need to do to make sure we handle everything related to our script subscriptions is if we search for to-do you&#39;ll notice we need to remove our stripe subscription on this particular page when a user deletes their account this is actually super easy to do with stripe so we can come all the way up here we can import stripe from stripe there we go and then we can say that we want to get a small stripe by creating a new stripe with our EnV that is coming from here EnV dot we want to get our stripe secret key so now we have a new stripe instance we can work on and down here we can just say stripe do subscriptions dot whoops Not subscription items we want to get subscriptions. cancel and we just pass it in the ID of the thing that we want to cancel so that&#39;s actually relatively easy so before we delete our user we want to do that all the way up here and we can say const user subscription equals get user subscription and we want to get the user subscription for our user ID which is our event. data. ID there we go give that a quick await and then with our user subscription we can pass in the stripe subscription ID but we only want to do this if our stripe subscription ID is not equal to null there we go so now if we have a user subscription and the ID is not equal to null then we&#39;re going to go ahead and we&#39;re going to cancel that subscription for them we can just throw a quick await on that and that&#39;s all we need to do to get that to work there we go we can remove that to do and luckily that was super straightforward and we&#39;ve actually done everything we need to do with our entire subscription section we don&#39;t have anything left the only two sections we have left is going to be our analytics and it&#39;s going to be the thing that allows us to render the app application the banner on another person&#39;s website now that sounds like it&#39;s going to be really complicated but it&#39;s actually not that bad and the amount of code for it is going to be essentially one single file so let&#39;s go ahead and work on making this actually show up on other people&#39;s websites so we&#39;re going to close out everything we&#39;re kind of at almost a new chapter of this application and inside of our API we&#39;re going to create a brand new folder and this is going to be for products slash we want to get our product ID and we want to get the banner and then directly inside that Banner folder we can create a file called route .ts this is going to be for rendering out our entire thing so we can just say export function this is going to be an async function called git this is going to retake in our request which is a next request and it&#39;s also going to take in our prams which is our product ID so we can say product ID is a string there we go looks like I have some spelling or things wrong get that spelled properly to pams and make sure I also hook all this up correctly looks like I&#39;m just missing a parentheses or not a parenthesis there we go bracket and it looks like I also forgot another bracket right there there we go now we can give that a quick save and that&#39;s all of our parameter information taken care of now the first thing I want to do is get our headers so we&#39;re going to say headers just like that then what I want to do is I want to get whatever URL the person is calling our page from because what&#39;s going to happen is on our products page they&#39;re going to come to our products page and click add to site and they&#39;re going to copy this code and they&#39;re going to paste this code in their application and it&#39;s going to call our site now we want to determine what URL they&#39;re calling us from because that is important in determining which product they&#39;re associated with and we want to make sure that the product associated with this URL is only ever called from that URL so let&#39;s get the requesting URL and this is a little bit complicated to get from our headers map what we need to do is we need to get either the F that&#39;s where they&#39;re coming from or we need to get the headers map. origin and this again is going to be where they are coming from one of these is going to give us the correct information on where they&#39;re coming from if neither of these have information so if our requesting URL is equal to null then we can just return not found essentially anyone that calls this code not from the correct URL or if they don&#39;t have a URL they&#39;re going to get the code not found the next thing we need to do is determine what the country code for the user is going to be so we can say get country code and we&#39;re going to get that based on our request and let&#39;s create a function for that get country code there we go this is going to take a request which is a next request and then inside of here we have information that&#39;s really useful we can say Geo and this is going to give us their country and here we can say if that is not equal to null then we can just return the request. goo. country so if they have a country associated with them it&#39;s going to return that now unfortunately this does not work in development it&#39;ll always return null in development and that&#39;s because it depends on your actual hosting provider to provide this information so versel for example if you deploy to versel they will fill in this go information for you so for testing purposes if our process. env. node environment is equal to development well in that case we&#39;re going to return EnV and make sure we get that from our server we&#39;re going to return our test country code so for some some reason we&#39;re not able to actually get our country we&#39;re going to return to them a country code so for example in development and then when you&#39;re in a real world application this should fill in its information for example if you&#39;re on ver cell so now let&#39;s implement this test country code inside of our environment variables on our server test country code z. string there we go and then inside of our EnV folder or EnV file I&#39;m sorry I&#39;m going to create another section that&#39;s called development test country code and for now let&#39;s just say that I&#39;m currently residing in India so that way we can test what that looks like we can bring this entire section over into our example and paste this in for example just like that so now we can test what this code will look like and here if our country code is equal to null again return not found because we were unable to find the country code for this particular user based on their Geo information so we don&#39;t want to do anything now the next thing I want to do is call a rather complicated database query that&#39;s going to get our product our disc account and our country based on whatever ID and country code we pass in so that&#39;s a rather complicated function that we need to worry about creating so we can come all the way over into our server into our database go into the product section and let&#39;s create that exact function so all the way down here async function we want to get this this is the internal version of the function just like that and it&#39;s taken in two parameters an ID and a country code our ID is a string and our country code is a string as well now inside of here we&#39;re going to get some data that&#39;s going to be calling await dbquery and we want a query on the product table and we want to find the very first product where our ID is equal to the particular ID that we have here so what I can do is I can say where and I can make sure that I get all this as a function I want to get equals and I want to get my ID as an ID column and what I can say is equals my ID column is equal to my ID there we go that works super great so I&#39;m just getting the first product with that particular ID then I want to get only specific columns so I&#39;m going to say that I want to get the ID and the clerk user ID are the only columns I want to get from this so this is everything for getting our product next I want to get specific things for that for example I want to get all of my customizations I&#39;ll set that to true I also want to get my country group discounts I&#39;m again going to specify only certain certain columns so I&#39;m going to say that I want to get just the coupon and I want to get just the discount percentage those are the only things that I care about from my country group discount but I also only want to get the country group discount for a specific country so I&#39;m going to come down here I&#39;m going to get all my country groups just like that make sure I put this inside of an object there we go and for my country groups I want to get specific columns and actually I don&#39;t want to get any columns I don&#39;t want any colums from my country groups instead what I want to get from my country groups is the countries themselves so here countries and it looks like I might have a typo somewhere because this is not showing up properly let&#39;s see here country group just like that so yes it should be country group because there is only one country group per country group discount then I want to get all of the countries and for the countries I want to get Only The Columns of ID and name that&#39;s all I care about for my country I want to get just one country and that&#39;s because I&#39;m going to throw in a wear Clause here and this wear Clause is a rather simple wear Clause that essentially just gets me the country for a specific code so I&#39;ll say equal and code and I want to get it where my code is equal to my country code just like that so all of this rather complicated code all it&#39;s doing is getting a product the product customizations and the discount for the product for the particular country ID now I need to do a little massaging to make this data look correct so first I can get my discount and that is going to equal to getting my data and I want to get the country groups discounts. find and I want to find the discount where the discount. country group countries. length is greater than zero So based on my wear Clause here I&#39;m only getting the country with a specific code so only one of my country groups will have a country and it will have exactly one item in the array so what I&#39;m doing here is I&#39;m saying hey find me the exact group that has a country that&#39;ll be my active discount for this user then I want to get my country which is just getting my discount. country group and I want to get the very first country because I only got one now what I can do is I can get my product information so this is just going to be if my data is equal to null or my data. product customization is equal to null then I&#39;m going to return undefined otherwise I&#39;m going to return down an object that contains my data. ID my clerk user ID Which is my data. clerk user ID and my customization which is my data. product customization so this is all my product related information so down here I can return whoops return my product I can return my discount which is going to be if my discount is equal to null then return undefined otherwise return a coupon which is my discount. coupon and my percentage which which is my discount. discount percentage finally I can add in the country here as well I&#39;ll just put it at the top like that so now I have my product my country and my discount they all could be undefined if they&#39;re not able to be found but hopefully they are able to be found so here I should be able to call this function actually after I create the internal version so I have the internal version I need to create the non- internal version so we&#39;ll just come up here copy one of these that&#39;s the create one we don&#39;t want that we&#39;ll copy this get right here and this one I&#39;m essentially going to call this function so it&#39;s going to call this particular function this is the non- internal version and for my tags I need to see exactly what I&#39;m using also I want to make sure my props are exactly the same so I&#39;ll copy the props paste those into here and then make sure I pass those props into my cache function now for this one I&#39;m getting a specific or specific ID here so I can say get ID tag and pass it in my ID I also am getting information from my countries so I need a global tag for that Global tag get Global tag there we go and this one is for my cach key tags. countries I need to do the exact same thing for my country groups because when either of those change I obviously am querying both of those datas so now with that done hopefully once I close all this down go back over to here I can import this and this will essentially get me my product my discount and my country but any of them could be null the first one I&#39;m going to check is if my product equals null if my product equals null then that means one of a few few things number one this is a bad product ID and it doesn&#39;t exist or two it means that the page that this information is being loaded on does not line up with the actual user ID that we&#39;re associated with so obviously that would be another problem and actually I just realized we&#39;re not even using our requesting URL so I should make sure I pass in the requesting URL to this function so this should take in a URL which is a string and that should obviously be passed down into here as well and then the internal function should take in a URL and here it should take in the URL because I only want to get this where the URL is also equal so we&#39;ll say URL as our URL column we can add in an and here and we&#39;ll say and are equals for our URL column is equal to our URL that way this only loads on the specific URL that we specified so now if we go back into here and our product is equal to null that means that we either loaded it on an incorrect URL or the user doesn&#39;t have access or something like that so again return not found now if we do have a product though that means that we can actually log this as a view for our users so we can say create product view this is going to be a function we&#39;re going to create in just a second because this is going to count towards their subscription usage if they go to the subscription page here it&#39;s going to count against their monthly usage so we can say for a specific product ID we&#39;re also going to do it for our country ID which is country. ID and this country ID could be null which is perfectly okay and user ID which is our product. clerk user ID now the reason it&#39;s okay that our country IDE is null is if for some reason the user coming from a country that we don&#39;t recognize in our database we still are going to log that as a view to the particular user and we&#39;ll just Mark that as undefined inside of our database that&#39;s how the parody deals clone is or that&#39;s how parody deals the actual site works so that&#39;s how our site&#39;s going to work as well you could change that if you don&#39;t like how that works so let&#39;s go into our product views and we need to create a function for creating things so export async function this is called create product view just like that and I&#39;m actually just going to paste this code in it&#39;s super simple we take in the product ID country ID and user ID and all we do is we just insert that into our database and then we revalidate our cache for that particular product View and we can even do it for the ID as well I didn&#39;t include that in here so let&#39;s throw in the ID so instead of row count here we&#39;re going to be returning and we&#39;re going to get the ID which which is our product view table. ID just like that so this is going to give us an array with an ID just like that so if our ID actually let&#39;s just call this new row there we go new row is not equal to null then we can pass along our new row. ID there we go now that&#39;s working much better we&#39;re creating our product View and we&#39;re making sure we&#39;re setting all of our caching information now back in our route here we can just make sure we create that ra row just like that now the next thing we need to do is to check to see if they can actually show this Banner so I&#39;m going to come in here I&#39;m going to say can they show the banner which is something that I&#39;m going to create a function for just like this can show discount banner and then here we have the ability to do all this stuff so to get the can show discount Banner I&#39;m actually going to do that up here can show Banner is equal to that so this can show Banner function is just a permission we need to create so let&#39;s do that real quick and then I&#39;ll explain how all the rest of this code is working so inside of our server we&#39;re going to go into our permissions export a async function can show banner and that&#39;s going to take in the exact same user ID all the rest of these take in and I&#39;ll just copy this code because it&#39;s very similar so instead of getting our product count we&#39;re going to get our product view count just like that and this is a function that we&#39;ve already implemented I just need to make sure I pass in the start date and this is going to be a new date and this is going to be start of month there we go so just getting all the count for the entire month there we go I just realized while editing this video that I actually forgot to update this tier section down here so this should be called the product views and then obviously the product views must be less than the maximum number of views that they can have so max number of visits I forgot to update this when I was doing the video but here is the updated code and when you download the code from GitHub it will be up updated now if we go back to this particular page we can import this function and this will return true if they have less than in our case 100,000 pricing page visits so first we check how many pricing page visits they have and make sure that they have few enough that we can actually do this then we add a brand new visit to it and then if we can show the banner we&#39;re going to make sure we do so if we can&#39;t we return not found if our country or our discount is null we also return not found and then finally we get to the point where we return JavaScript down to the user all of this code up here is just checking to make sure can this user see this JavaScript then we can actually return the JavaScript so I&#39;m going to call a function called get JavaScript just like that and this is going to take in our product our country our discount and it&#39;s going to take in can remove branding as well which takes in our product. clerk user ID there we go so now let&#39;s create this simple function we&#39;ll do it down here just like that now for our actual typing of everything I&#39;ll paste that in we have our product which has all of our customization information our country name our discount and if we can remove The Branding then inside of here what I want to do is I want to take my banner component and render it as static markup so there&#39;s a function called render to static markup and we can get this here from awaiting the import of react-dom server there we go and now you may think why would I await this import directly inside of here when I could just just import it at the top of my page and that&#39;s because nextjs actually prevents you from importing this function if you import it it immediately crashes your site it&#39;s annoying I don&#39;t know why they do that but if you want to be able to import this function you need to actually do it in this Dynamic import way so that&#39;s why we&#39;re doing this to get around next js&#39;s limitations then we can return some string and the string is just going to be JavaScript code so I can say const Banner is equal to document. create element and we&#39;re going to create a div and this is just code that&#39;s going to run on the user&#39;s browser then I can come in here and set the inner HTML inner HTML is going to be equal to and this is where I want to render all of my stuff to a static markup so inside of here put some quotes like that and I can say render to static markup and I can pass it in create element whoops which allows me to pass in my element which is a banner that&#39;s my component and then we need to pass in all the props for this particular component that we want to render so let me make sure I get all my parentheses closed up there we go so now inside of here I can pass along my message this is my product. customization location message then we have my mappings so our country maps to our country. name my coupon maps to my discount.on and then finally my discount Maps 2 taking my discount. percentage multiplying it by 100 just like that and let&#39;s make sure this is spelled mappings and this actually needs to be a string so we&#39;ll just convert this to a string there we go that gives us our discount information now we can pass along our customization which is our product. customization and then finally can remove branding whoops remove branding is the last thing we need to pass along so this is all the stuff to pass along to create our Banner now that we&#39;ve created our Banner with all the inner HTML that it needs needs we can come in here and we can do a quick document. query selector we want to get a query selector specifically for whatever our product. customization Banner container is so I want to search for that Banner container I then want to prepend onto that all of the children of my banner component just like that so essentially I&#39;m creating this Banner component filling it with all my HTML and taking everything from it and prepending it to the beginning of this there we go and now the final thing that I want to do is I just want to call replace just like this and I want to remove all the white space information from here that I don&#39;t actually need so I&#39;m just going to copy over this quick replace statement this replace statement just gets rid of all the additional new lines in my code to make sure everything is super clean and tidy because obviously with using this syntax right here of these back ticks it actually leaves new lines in your code and JavaScript won&#39;t know how to parse that potentially so I&#39;m just getting rid of all those new lines and this right here is going to return to me some JavaScript that I&#39;m getting right here for my response and the last thing I need to do is make sure I tell my response that this is Javascript so in my headers I&#39;m going to pass along the content type header of text/javascript so I&#39;m essentially anytime someone calls this API they&#39;re either going to get not found or a bunch of JavaScript on their page so now let&#39;s test and see if this actually works I&#39;m going to go over to my products page I have this product right here for Local Host 5500 I&#39;m going to try to add that to a site and click copy code now this is a site right here that just has some random text on it I&#39;m just going to paste this JavaScript script tag right into here that&#39;s all I need to do and now I can essentially access this site on Port 5500 so if I open that up this is that site being accessed on Port 5500 and when I refresh it&#39;s currently not showing me my application I&#39;m at the URL 1271 5500 and if I look here it specifically specifies the URL must be Local Host 5500 so let&#39;s make sure we go to Local Host 5500 and see if that works you you can see we&#39;re on that Local Host and it&#39;s still not working I think part of the reason why this is is because we need to make sure we remove the trailing Slash from our requesting URL so when we get our product Banner we have our URL here and all the way down where we&#39;re using that internally I want to make sure that we remove the trailing Slash from it whoops that&#39;s the wrong one product Banner there we go and here I want to say remove trailing slash and pass in my URL just to make sure that&#39;s not the potential problem we&#39;re having let&#39;s refresh it looks like that didn&#39;t fix the issue so now the best thing that we can do is just add in some console logs to see what&#39;s going wrong the very first thing is just let&#39;s see if we get to this particular point we&#39;ll just say hi right here give this a quick refresh check out our console and see we are printing out high so it&#39;s getting to that point let&#39;s get to this point and we&#39;re going to print out our product hopefully this prints out something instead of null we&#39;ll refresh and we&#39;ll scroll up and we do have all of our product information so we know we&#39;re getting to that point that&#39;s working fine the next step is we can down here and see can we show the banner so let&#39;s check to see if that works give that a quick refresh and it says we can show the banner so now let&#39;s check to see if our country and our discount are possibly set to null so give this a quick refresh here and it looks like in our case our country is India and our coupon is set so obviously all of that is correct we&#39;re getting all the way to this JavaScript section so maybe something in our JavaScript is actually Incorrect and if we look unexpected identifier text you can see there&#39;s currently a problem with our code so let&#39;s go to the sources Tab and see what are actual JavaScript looks like that&#39;s being imported so we give this a quick refresh pull this over and you can see Local Host 3000 it&#39;s importing this particular Javascript file so we&#39;re getting our document creating the element setting the banner HTML and as you can see I&#39;m using double quotes multiple times so I need to get rid of one of those sets of double quotes so here change this to single quotes change that to single quotes that should fix the problem refresh and you can see hey our Banner is showing up and it&#39;s being stuck directly to the top of the page which is exactly what we want if we were to go ahead and then change change the url of this so let&#39;s say edit and we&#39;re going to change the url so it&#39;s only on 5501 give that a quick save it&#39;s been updated now if I come back to here and refresh you can see it no longer shows up on our page also if we go to our subscription you can see we&#39;ve had seven monthly usages because we viewed this page seven separate times and if I refresh this a bunch of times you&#39;ll notice it doesn&#39;t actually add any usages as you can see here it&#39;s still set to seven that&#39;s because it&#39;s not able to show because the URL is incorrect but if I were to go back to our product change the url back to what it should be so we can edit this back to 5500 click save now when I go here and I refresh the page a couple times showing this banner and go back to my subscription you can see now we have 11 out of 100,000 pricing page visits so now the nice thing here is we&#39;re finally to the last section which is just dealing with our analytics and honestly it&#39;s not too bad other than a few rather complicated javascri I&#39;m sorry SQL queries really that&#39;s the only thing complicated about all of our analytics so let&#39;s just make this a little bit easier to work with we&#39;re going to minimize and close everything down again because we&#39;re kind of at a new section and what I want to do in my dashboard is create a new folder called analytics and inside of here I&#39;ll create a page. TSX so we&#39;ll export a async function make sure it&#39;s default this is going to be called analytics page now this is going to have some search prams on the page so we&#39;ll say search prams just like that and to type out our search prams whoops search prams we&#39;re gonna have a few different parameters first of all we&#39;re going to have an interval so do we want to do it last s days last 30 days and so on which is going to be a string we&#39;re going to have a time zone which is going to be a string and we&#39;re going to have a product ID which is going to be a string and all of these are optional whether or not we specify them or not it doesn&#39;t really matter so here&#39;s our analytics page let&#39;s come in here return null just so we have something showing up and if we go to that page you can see it&#39;s showing nothing now just like with all of our Pages we&#39;re going to check for our user ID using this off to make sure we have access to that to do all of our different queries that we need now for our application I&#39;m going to come in here and I&#39;m just going to render out a simple H1 for the analytics at the very top of our page so we have that showing up and then what I want to do is I want to check to see if the user has permission and the permission is going to be the can access analytics permission if they have access to that I&#39;m going to render this otherwise I&#39;ll render out a fallback and inside of here I want render out essentially a flex column grid layout so Flex column with a gap of eight and inside of here I want to render out each of my different grids inside of a card I&#39;m sorry each of my different charts inside of a card so we&#39;re going to have like a views by Day card and we&#39;re going to render out all the information for that make sure I spell that properly we&#39;re also going to have different charts as well so here we&#39;re going to have a views by PPP card and then finally views by country card there we go so we can determine where all these views came from for different analytics sections now each of these cards is going to be nearly identical I&#39;ll Pace down exactly what they look like and I&#39;ll cover each one of them individually so for our cards we just need to make sure we import all the different things that we&#39;re using inside of these cards and then finally each of these cards has essentially three different things that go on first we have chart data that we need to get based on a function that&#39;s accessing our database we&#39;ll comment that out for now as well as the props that we have the next thing we have is a card that says like visitors per day and then it renders out what that chart is given the data we get from our database and as you can see this exact same pattern repeats for all three of our different charts so each one of them renders out a card it gets data from our database and it puts that inside of a chart so if we remove that you can see we just have titles with no charts at all so that at least is giving us a starting point for our application so to get started I&#39;m going to focus on the views by country card because that is going to be the easier of the ones to implement and then once we understand how that works the rest of them should relatively fall into place so let me make sure I get our props in here just like that make sure that they have all of the typing information correct for them there we go that&#39;s exactly what we need so now we need to create this git views by country chart data that&#39;s going to be inside of our database folder so in our server in our database and our product views that&#39;s where we&#39;re going to access this information we can just minimize all these ones that we already have existing and I want to create a brand new function export function get this information just like that and this is going to be pretty much exactly what we have up here but obviously the internal function is going to be this internal function the tags I&#39;m going to come back to so we&#39;re going to get those in a little bit and then we want to make this internal version of the function now before we start working on this function the very first thing we need to do is to specify a constant variable called chart intervals and this is just going to make it really easier for us to swap between like last 7 days last 30 days and so on so for example I could say last s days and that is going to have information like a label which is last 7 days and it&#39;s going to have a start date for example make sure I spell that properly so we could say start date is going to be sub days and we&#39;re going to take a new date and we&#39;re going to subtract 7 days from it so this is essentially going to be 7 days ago now we obviously want to do this for all the different fields we&#39;re going to have I&#39;m only going to be creating three just because it&#39;s going to be simpler but you can create as many as you want so let&#39;s go all the way to 365 this one is subtract 30 days last 30 days last 365 days is going to be 365 just like that so now with this chart interval we essentially can get all the information we need for how to do these queries and how to display them to the user so let me get our props typed into here we have our time zone product ID user ID and interval and the time zones required product ID is optional because we can do something for all the products instead of just one our user ID is required and the interval is is essentially just going to be either last 7 days last 30 days so on if I hover over the type you can see it&#39;s going to be one of these different types of intervals so it&#39;s going to be the data directly inside of one of these different intervals now this is going to be by far the most complicated query these three queries are but the nice thing about these queries is that we have drizzle which makes writing complex queries possible and easier than anything else so the very first thing I want to do is convert everything to the correct time zone so I&#39;m going to get my start date which is a start of day and I want to get that to a zoned time that&#39;s going to come from a new library so we&#39;ll come into here we&#39;ll just cancel out of that stripe stuff npmi dat FNS TZ that&#39;s the time zone specific version of the library and we&#39;re actually getting an error and that&#39;s because we don&#39;t even need this Library anymore literally today as I&#39;m recording this they updated the date FNS library and added time zone support so we don&#39;t actually even need this Library anymore and we can do this directly in date FNS so to get the start of the day we&#39;re going to say new date just like this and actually this is not a new date this is our inter dat so we&#39;re going to get the start of whatever our start date is and then we&#39;re going to convert that to our time zone so we can just say in TZ which is coming from date FNS we&#39;ll have to probably manually import this import TZ from date FNS SL TZ and it&#39;s going to be at dat FNS TZ so we just put an at at the front of that and we will need to actually install this Library so we&#39;ll just come in here install the new date FNS Library that&#39;s built into date FNS which is incredibly nice make sure I all that properly that should install the brand new library for us there we go so now what I can actually do is make sure that this Imports properly looks like it did and down here I can call this TZ function and pass in our time zone there we go it&#39;ll now convert this to the correct time zone the next thing I need to do is to actually get a subquery so I&#39;m going to get our product subquery there we go this is going to be equal to calling get product subquery and a subquery inside of drizzle is just a way for us to combine multiple queries together in an easier to use way I&#39;ll show you what I&#39;m talking about so we&#39;re going to get a user ID which is a string I&#39;m sorry we don&#39;t need to type this here and a product ID whoops product ID there we go so now we can create this function function just like that this is going to take in a user ID which is a string and a product ID which is a string or it&#39;s going to be undefined there we go and now what we can do in here is we can return d Dot and there&#39;s this dollar sign width we need to give it a name in our case it&#39;s products and then we can specify what we want this to represent and this is just another DB query so in this case we&#39;re going to be selecting all of the products that we can actually access using this user ID and product ID again we&#39;re breaking our query down into multiple smaller chunks which makes working with it much easier so we&#39;re going to be selecting from the product table all of the information where and we want to do an and query and an equals query make sure I import equals there we go and we we want to check to see when the product table. ID or I&#39;m sorry user ID is equal to our user ID just like that and we also in here need to add another check but we only want to add this if our product ID is not equal to null so if it&#39;s equal to null we&#39;re going to return undefined otherwise we&#39;re going to return our product table. ID is equal to our product ID so what this is doing is going to check okay get all the products for our particular user and if we passed along a product ID only get the product for that specific ID so this right here is going to be a subquery we can use that gives us all the valid products so here is essentially a limited list of the products that we have access to I&#39;m then going to create another subquery but this one is for our product views so we&#39;ll call this product view subquery I might as well just call it SQ same thing up here just make it a little bit easier to work with this is going to be another DB this time I&#39;m going to say DB dollar sign width this one is product views and then this one is going to be as another DB and to be able to combine together subqueries so if I want to use this products subquery in my new query I can just say with and pass along the product subquery so products subquery just like that so now I have this as a table that I can join on and so on so what I want to do is I want to select some information I&#39;ll get to what I&#39;m selecting in just a little bit I want to get it from the product view table and I want to do some joins so I&#39;m going to put an inner join here on my product SQ so I&#39;m going to be joining on this particular table this subquery that I created where my subquery whoops subquery doid is equal to my product view table. product ID so here I&#39;m joining these two tables together so I have a limited list of only the products that I have access to and I&#39;m combining them with my product view table to get all the product views for the products I have access to then I want to get the information for the country as well so I&#39;ll join my country table where my country table. ID is equal to the product view tablecountry ID so now I&#39;m getting all my product and Country information from here and I only want to get it where the visited at row visited at row right here is greater than or equal to visited at and start date there we go so how do I get this visited at row well that comes from my select I can come in here and say that I want to get a visited at row and this visited at row is going to be some custom SQL because I need to convert everything using time zones so I&#39;m going to pass in my product view table. visited at and I want to convert it to a Time Zone by saying at time zone and passing in the time zone that I want to convert to now to make sure that everything lines up and works properly I need to actually inline my parameters here so that way it knows what time zone to convert to and I need to give this an as property just to make sure that it actually will render properly if you don&#39;t give your custom SQL an as property it won&#39;t run inside of drizzle so this gives me my visited ad converted to the correct time zone and I&#39;m comparing it against this time zone right here the next thing that I need to do is to get my country group ID which is my country table. country group ID I want to get my country name which is my country table. name and then finally country code which is my country table. code so this is just getting all the information for each one of the visits on my particular website based on the name and code as well as the group ID that&#39;s associated with them so with this product subquery I have my products and with this view subquery I have all the views now I just need to get the data that I want so here I can return Calling await DB dowith and I want to use that product view subquery that I just created and I want to select only specific columns I want to get the country name which is my product view subquery do countryname I want to get my country code which again is my product subcount code and I want to get my views which is just going to be a count of all of the different visited at rows that I have inside of here so visited ad there we go make sure this is an async function so I can return that awaiting that I have here so I&#39;m selecting all those rows I want to start with my country group table just like that and I want to do a join on my product view just like that and I want to get where it&#39;s equal my product View whoops product view subquery doid or I&#39;m sorry country group ID is equal to my country group table. and actually I don&#39;t even think I need to do this additional step of joining on this country table CU I&#39;m not actually using the country table data so I can essentially remove all this information about the country group I don&#39;t need any of that so I&#39;ll get rid of this all my SQL for my visited app I&#39;m actually just going to put in line directly right here so I can get rid of all of that right there so that&#39;s SQL has been directly inlined there and instead I&#39;m just going to change this to be my count and this is going to count essentially the visited at row itself so this is going to be my product view table. visited at because I don&#39;t care about the time zone when I&#39;m doing counting so I don&#39;t need to convert the time zone at all then what I can do I don&#39;t need any of this particular code I already have the country name and country code up here so I can get rid of all of this I can make sure that this is not even a subquery so I can just get rid of all this subquery related stuff here we go just call a wait on this and return this so this should be a little bit simpler than what I had before there we go looks like I&#39;m probably missing missing a parentheses or bracket there something is being missed completely here let&#39;s see parentheses parentheses maybe I have an extra set of parentheses there we go so I have all my joins I have my wear Clauses all I have left to do next is to do my grouping so here I&#39;m going to do a group bu and I want to group by my country code make sure I spell that properly make that into a function and I also want to group by my country name so we&#39;re just going to put an array in here with our country code country name just like that and then I also want to order them and I want to order them by My Views which is going to be my account I might as well call this views though so here we go views and we&#39;re going to order in the descending order My Views there we go so whichever one has the most views is going to show up first in my list of orders and I also want to only get 25 just because I can only really fit at most 25 different countries in my chart so this right here I know it&#39;s a rather complicated query I&#39;ll go through it in depth first I&#39;m getting only the products that I have access to then what I&#39;m doing is I&#39;m counting up all my views for each country based on their name and code that&#39;s where this group by comes in I&#39;m only grouping by country name and code and for each grouping of country name and code count how many views have that country name and code then I&#39;m doing a couple joins here to make sure I&#39;m only joining on the products I have access to and I&#39;m joining on the country table to get information for the country this little query right here is making sure I only get data after my current start date and then I&#39;m just ordering everything in the correct order so that should be everything for this function I&#39;m going to copy over all of this into here so I can make sure I get all the props being passed down for both of these here same exact thing pass it in my props and then I need to figure out exactly what my tags are going to be so the very first user tag that I&#39;m going to have here is going to be for my user ID and the cach tags. product views because I&#39;m getting all the product views I&#39;m also going to have an ID tag so get ID tag that&#39;s going to be for my product ID if there is one and then I&#39;m going to get my cach tags. products there we go and this particular tag is going to depend on if there&#39;s a product ID or not so if product ID is equal to null then I&#39;m going to render out a git user tag for my user ID and the cach tag tags. products there we go so essentially if I have a product ID give me the tag for that one otherwise give me a tag for all of my users products then I want to have a global tag that&#39;s because I&#39;m getting all of my countries so Global tag on my cach tags. countries there we go so that&#39;s everything that this particular function is using and hopefully with all of that done we should hopefully see back onto this page if I import this function maybe I&#39;ll have to import it right here there we go give that a quick import and make sure I get the correct information up here there we go that should give me all the different props I need all I need to do is create my actual chart and pass in the correct props up here so if we look at this you can see I have my interval that I need to pass in I have my time zone that I need to pass in my user ID and my product ID so we already know the product ID that&#39;s going to be my product ID that&#39;s coming from my search pams and to make it a little bit easier easier we can actually just get that information out here so we can say my time zone is going to be my search time zone or UTC by default and my product ID is going to be my product ID so I don&#39;t even need to get that for my search frames anymore same thing for time zone that&#39;s just going to be my time zone my interval is going to be a little bit more confusing so interval is either going to equal chart interval and I want to get it for my search prams whoops search prams do interval just like that or if this doesn&#39;t exist I&#39;m going to get my chart interval. last Days by default now this you can see is throwing me an error because this must be of the key of type of chart intervals so I&#39;m just going to manually cast that saying hey it&#39;s one of these and if it&#39;s not just give me essentially something that&#39;s from the last seven days now I&#39;ll expand my screen a little bit so all the code fits on one line looks a little bit cleaner that way and my interval I can now pass in just like that and the user ID I already have access to that just like that so now I have all the information I need inside of here if I scroll all the way down I have my chart data which is views country name country code now all I need to do is render this in a chart and we&#39;re going to use Shad CN for all of their charts now to add Charts it&#39;s relatively easy we can just call Shaden add chart that&#39;s going to add the charts into our application and then working with the charts is not too difficult let&#39;s make sure we don&#39;t overwrite any of the files we don&#39;t want to overwrite and now we can create this chart Library function so inside of our components we&#39;re going to create a brand new folder called charts and inside of here is we&#39;re going to render out our view actually I think I copied it so there we go TSX this has to be a client component when you&#39;re dealing with charts and then we can export that function just like this now this chart function is going to take in our chart data as its only prop and the type of this chart data is going to be a country country code which is a string it&#39;s going to be a country name which is a string and it&#39;s going to be views which is a number make sure I spell all of that correctly and now inside here we could just return null for example and at least that&#39;ll render out properly and it&#39;ll let me import this right there it looks like our chart data is maybe not lining up properly let&#39;s make sure I spelled country code country name and Views that looks like it was all spelled correctly obviously it should be an array of data though that fixes all the errors that I had inside of here so now let&#39;s go ahead and Implement what our chart should look like so the very first thing I want to do for this particular chart we possibly could have no data at all so I&#39;m going to say if our chart data. length equals zero just render out that there&#39;s no data and we&#39;re going to put that in the middle of our screen next what I want to do is I want to render out a chart container which comes directly from Shad CN this chart container takes two things the first is a config which is how it hooks up different things so we&#39;ll say chart config just like that and then finally we need to specify some class names and if you want things to be responsive you generally need to have a minimum height so we&#39;ll say Min height of 150 a Max height is going to be 250 pixels whoops 250 pixels there we go and we&#39;re also going to say that the width is is full so it spans the entire container now to get this chart config we can come up here we can say con chart config equals and essentially for every single row or type of data that you have you need to have a chart config with a data Row in it so in our case views is the only thing that we&#39;re showing inside of our data as a bar in our bar chart so that&#39;s the only thing I&#39;m going to set a column for here so I&#39;m going to say views and I&#39;m going to give it a label which is visitors there we go and then we can give it a color in our case I&#39;m going to use use the HSA color which is based on our accent variable there we go so now we have our chart config and everything done inside of our chart container we need to render out a chart and in our case we&#39;re going to use a bar chart from recharts that&#39;s the library behind the scenes we want to render out the accessibility layer and then our data is just equal to our chart data there we go now inside of this bar chart we want to render out what our xaxis is going to look like our data key in this case is going to be country code so it&#39;s going to put the country code on the x-axis we&#39;re going to say that for a tick line we&#39;re going to set that to false and then finally our tick margin is going to be equal to 10 just to space things out a little bit now let&#39;s just make sure we close that off and import our X access and now we have that showing up you can see this column visited at does not exist so there&#39;s problems with my query that I need to fix so let&#39;s go ahead and actually fix that before we go back so inside of product views here we can scroll all the way down and it&#39;s saying that this visited at column when I doing my count on does not exist I think I may just be able to remove this as section right here because I don&#39;t actually need that now that it&#39;s no longer in my select statement and that may actually fix the problem and it looks like that did and you can see down here visitors per country we have India showing up that&#39;s the only country I&#39;ve faked doing anything from so right there we can see that that is showing up there&#39;s some other errors inside of this looks like just some typing errors that should hopefully resolve itself in just a second but for now I&#39;m going to go back and finish out the rest of this chart so we&#39;re going to come in here with a Y AIS so we can actually see our bars so we&#39;re going to have a tick line equal false on this one we&#39;re also going to come in here make sure I import this there we go we&#39;re going to have a tick margin of 10 just like the other one we&#39;re going to make sure allow decimals is set to false it doesn&#39;t make sense to have half of a person so obviously get rid of that and our tick formatter is going to format this as a compact number because these numbers could get quite large there we go that&#39;s our y AIS done next thing we&#39;re going to render is our bar that&#39;s probably the most common thing we want to render so we data key for this one is going to be views that&#39;s just whatever we have here that&#39;s our number views that&#39;s what we want to render here so for the fill of this particular thing I&#39;m going to set this to the variable which is our color views there we go and that is just based on let we close that off real quick that is based on whatever we put for our color inside of here so color views there we go now we give that bar from recharts give that a save and now you can see that we have this showing up the last thing I want to do is add in a really nice looking chart tool tip so our chart tool tip is going to have some content and inside that content is our chart tool tip content directly from Shaden and the label key is going to be country name there we go so now whenever we hover over this it&#39;s going to use the country name instead of the actual country code I believe the reason we&#39;re having this problem is because this should say name key instead of label key let&#39;s see if that fixes it and there we go it says I in this should be our country name though not our country code let&#39;s try refreshing that to see if that works maybe there&#39;s something wrong with the data coming back so let&#39;s console.log our chart data to see if maybe there&#39;s a problem with our chart data we can just come in here look at our actual page inspect that go over to the console look at this array you can see it has country code and country name so that is correct it should be getting the name to be the country name let&#39;s try setting both the label key and the name key so we&#39;ll say Here country name just like that that&#39;s not working either so that&#39;s obviously not ideal so I think our label key is just not pulling in the correct information honestly not a huge deal we can just leave it as is give that a quick save and it&#39;ll just say I in instead now let&#39;s close out of that and make sure all of our typescript errors yeah we have no more typescript errors it was just some weird typescript compilation thing but we have our entire chart done now to be able to make sure that this works for multiple countries I&#39;m going to go into my environment variable I&#39;m going to change this to be like us for example so now we have us and India both showing up so if I come over to here and refresh my page you see I get no Banner oh there we go it is actually showing up you can see I get a banner for this particular discount code and now hopefully if I come over here you can see we have 11 visitors from India and one from the US so this is working as we expected to for different parody groups in different countries the next thing we have to do is to implement our last two charts and we&#39;ll do the visitors per PPP group because it&#39;s actually relatively similar to the chart that we already created so what I&#39;m going to do is I&#39;m essentially going to copy this entire function down and instead of saying country chart I&#39;m going to say PPP and I&#39;m going to come all the way up to here here where we have the non- internal version which is right here copy that paste it down and where it says country going to change that to PPP now I may need to change around what my different tags are so I think I&#39;m going to need my country groups for this one so we&#39;ll say country groups I&#39;m just going to preemptively add that in there we&#39;ll see if we need it or not so now we have my PPP version there we go close that down come all the way down to the PPP chart and this chart is going to be a little bit different because we actually will need multiple subqueries we&#39;re going to need to get our product View subquery and we&#39;re going to need to be able to get our normal subquery so this one&#39;s going to say with with a dollar sign product views. as and we&#39;ll put this entire query directly inside of here we can get rid of some of the stuff on this query like all this grouping by we don&#39;t need any of that and I do need to take all of this SQL that I inlined and move it back out so this is going to say visited at is that as visited at make sure I spell that properly there we go put a comma get rid of this views section right here and we need to make sure we have a DB just like that so now this greater than is going to be a function version which has our visited at takes a function and this function is going to call greater than with visited at start date there we go give that a quick save looks like all that&#39;s formatted now I don&#39;t actually need the country name or country code for this one but I do need the country group ID because I need to get the name of the group that&#39;s what this entire one is for the PPP group is our country group so country table Dot and I want to get the country group ID so essentially I&#39;m getting the visited at field and I&#39;m getting the country group ID and I&#39;m making sure I only get the ones that are visited after the specific date so now that I have that subquery I can return awaiting db. with this particular new subquery make sure I put it as a lowercase Q so it lines up with the rest of my formatting I did I want to select specific Fields we&#39;ll leave that blank for now and we&#39;ll come back to it and the most important thing is I want to get this from the country group table so there we go from our country group table and I want to specifically join with the other table that I already have and in this case I want to do a left join instead of an inner join on that product subquery and I want to do it where my product subquery dogr ID is equal to my country group table ID and the reason I&#39;m doing a left join here instead of an inner join is I want to get all of my country groups and display them in my chart so even if I have zero views from the 30% group I still want to show that on my chart as a null value so that&#39;s why I&#39;m getting this as a left joint because this is going to give me every country table even if there are no views associated with it if I didn&#39;t an inter jooin instead it would only give me the tables that have or the country tables that have an actual product view associated with them which is not what we want so now what I can do is all of my grouping so in my case I want to group by a specific field so we need to do our select first so I want to get the PPP name which is our country group table. name and I also want to get my views which is going to be calling count on my product views. visited field so now here I can do a group bu which takes in a function we want to get that visited not visited at the PPP name that&#39;s what I want to group on so we&#39;re going to say PPP name just like that that&#39;s my group by field and then I also want to order so I&#39;ll come in here with an order by and I want to order by this particular field as well so there we go and that&#39;s all it takes to be able to implement this function you can see it&#39;s nearly identical to what we did before all I want to do is just get the country groups instead of the individual countries so we can minimize that down and we can actually use that inside of this particular page so the PPP chart and all these parameters information we can use so I&#39;m going to take these props move them up here there we go make sure that I get the data from the corre cor chart same thing there and now I need to make sure I get all the information I need from up here so just going to copy this information paste it down in there it should be all the exact same information and I might as well do the same thing at while I&#39;m at it for this chart because it&#39;s obviously going to be the same data for that chart as well so now let&#39;s implement this chart and again I&#39;m just going to copy my existing chart because it&#39;s going to be somewhat similar so this one is views by PPP there we go views by PPP chart and now I want to get all my chart information but in this one it&#39;s going to have a PPP name instead of the country name and country code so same thing for my chart config that&#39;s going to be the same this data should never be null because as long as I have a country grouop it should show up but just in case I might as well just leave it in there then the next thing is I want to deal with having my chart so my xaxis is my PPP name and nothing else and that should be the only thing I need to change for this chart to make it actually work so let&#39;s give that a quick save and see if it works says views by PPP chart obviously I need to import this component there we go now if I give it a save we give this a quick refresh you can see that now it&#39;s actually showing all my different parody groups between 23 all the way all the way up to point or 1.1 now I do want to make one slight modification to the way that this chart data is showing up so inside of this function here I want to just create data which is equal to chart data map over each data point I want to return an object which is going to take all my normal data but I want to take the PPP name and I want to take whatever that name is and I want to make sure that I replace whoops replace parody group with an empty string and this should never be null so I didn&#39;t actually need this check there there we go so now essentially what this little bit of code is doing is removing that parody group colon section at the start I don&#39;t really like that and now I can use that as my chart data instead and if I give my page a refresh you can see that doesn&#39;t look like it quite worked that&#39;s because I forgot to put the colon here now we give that a save and you can see automatically it has already cleaned that up drastically and if I open this up you can see now it has made my labels a little bit easier to read and so on and I have had one visitor in the 0.9 to1 group and I&#39;ve had 11 visitors in the 2 to3 Group which lines up with my India versus US users so at least know that that is working now unfortunately this Visitors by day chart that we have next is going to be the most complicated chart that we need to work on so let&#39;s go back over to that product View and we need to essentially just copy over one of these charts let&#39;s just go ahead and copy this chart paste it down and this one is going to be get views by day chart and then we want to obviously copy up here the exact same thing this one is get views by day chart and we want to get the internal version of that now the tagging for this one is going to be a little simpler and that&#39;s because this table doesn&#39;t query any any of our country or country groups all it cares about is views and days so it only queres our product and our product views table so at least our caching is slightly simpler but that is about the only Silver Lining because this is by far our most complicated function we still need to be able to get our product subquery but we don&#39;t actually need our start date because of the way that we&#39;re going to be writing this query and the way we&#39;re writing this query is we essentially want to generate all of the days within our interval so if it&#39;s like last seven days I want to generate seven days if it&#39;s to last 30 I want to generate 30 days and so on so I want to generate a series one for each day inside of my interval that way just like this chart has rows for zero I want to also show days that have zero visitors as well so this products subquery that we have right here is going to be really rather simple because I&#39;m not actually going to join on any country tables and I&#39;m not even doing any wear Clauses at all instead I just want to get every single view for all of my products that are in my product subquery so my country group ID is gone and this is replaced with a product ID that comes from my product subquery doid there we go and that&#39;s the only thing I&#39;m getting from here I&#39;m getting my visited at and I&#39;m getting my product ID the big query the more complicated one comes in this section right here so we&#39;re getting this with our product view so we have essentially every single view which has a visited that date in our time zone for every single product that we have access to then what I want to do inside of here is I want to select specifically a date and this date is going to be formatted in a rather different way than you may be used to so for now I&#39;m just just going to return this as undefined and we&#39;ll come back to this in just a little bit now for our from here again we&#39;re not going to be querying any of the tables in our database we&#39;re going to create our own J table of data essentially an array of data and we&#39;re going to get that from our interval and we&#39;re going to call that interval. SQL so each one of these is going to have a SQL section added onto it now this SQL section is going to actually call the SQL function and it&#39;s going to call generate series which is a postgress function which allows us to generate a series of data between a set of dates so what we can do is we can take whatever the current date is and subtract seven days because it&#39;s the last seven days and we can take that and go all the way up to the current date so essentially this gives me a series between whatever the current date minus 7 is and the current date and I can say I want to do this in intervals that are one day intervals so by using this code right here let me make this a little bit bigger so it&#39;s easier to see I can say that I want to generate a series between 7 days ago and today and I&#39;m using one day intervals which is a type in typescript or in postest I&#39;m sorry and I want to generate that with the name series because I&#39;m going to use that in other places so I want to do this exact same sequel in all of these other ones so down here and down here so now for my 30-day one it&#39;s really easy I&#39;m just going to subtract 30 days at one day intervals rather straightforward this one is going to be much more complicated though because instead of just generating this 30 days ago it&#39;s going to be 365 days ago and I want to do this using using one month intervals so here I can say that I&#39;m going to have a one month interval just like that but I need to be able to not just get the current date but I want to get what the current month is so what I can do is I can say date trunk that&#39;s going to truncate my date and I can say truncate at the month Mark just like that so it&#39;s going to take whatever this date from 365 days ago is and truncate it at the month Mark and it&#39;s going to return to me essentially a string with that same thing here I can do date trunk just like that I can truncate it on the month and that&#39;s going to be whatever my current date is truncated at the current month this just makes it so that now I can take any day in a month cut off all the day information and just be left with the month so now I can come up here I have the interval. SQL and this is going to give me an essential array of data between whatever the current day is and the day that I want to go all the way back to now the next thing I need is a way to group my days because all my visited at has time all the way down to like the millisecond so obviously no two dates are going to be exactly the same because they have millisecond level data so I want to be able to group my date using a date grouper function this is a function that&#39;s going to take in a column which is either going to be SQL code or SQL do alist code it&#39;s essentially just some random SQL code there we go make sure I import that type from drizzle and what I want to do is I want to convert this into something that will convert my date to a more uniform date type so in my case I want this to be individual dates instead of times I want to cut off all the time and get me just the date information so I&#39;ll say SQL with a type of string is going to return to me a new date object from postgress using my column and I want to make sure I inline the parameters here so what this little bit of line of code does right here is it&#39;s saying okay I have a date that&#39;s coming in that has like time stamp information all the way down to the millisecond and I&#39;m going to cut off everything except for the current date so this is essentially how the date trunk function works but it&#39;s truncating everything except for the date so it has like the year the month and the date but no time information I want to use the same grouping function for both my last 30 days and my last 7 days but when it comes to my last 365 days I want to truncate this using that date trunk function that we&#39;ve already used so I&#39;m going to say date trunk just like that I want to truncate it down to the month now the final thing I want is some way to format these dates so that I can easily display them inside of my form so I&#39;m going to come in here with a date formatter just like that and this is going to take in a date object from JavaScript and for example on this one I&#39;m going to use a month formatter and I&#39;m going to format my date so instead of typing out what the month formatter is I&#39;ll just paste it down here it&#39;s a new internationalization date formatter that&#39;s a two-digit year and a month that is short and the time zone now the reason I&#39;m using UTC as my time zone here which sounds really confusing is when I do these date truncations and this date here it removes all my time information so if I were to format this in a time zone that&#39;s not UTC it&#39;s actually going to move my date forward or backward like 3 or 4 hours and if it moves it backwards like 3 hours hours that now puts me the day before and that&#39;s probably the problem that parody deals has on their website so by using the UTC time zone it ensures my date won&#39;t actually move because I don&#39;t actually have a Time Value so that&#39;s why I&#39;m using time zone of UTC here to make sure my date does not move now the next two things I want to format as dates instead of months so I can just use the date formatter that I&#39;ve created so we have date formatter and date formatter and this date formatter just gives me a date style of short rather straightforward so now my chart intervals is much more confusing but it allows me to get all the data I need to actually use this form for example giving me that generate series and this also allows us to create what our date is going to be so I can take our interval and I can get our date grouper and I want to group my SQL do raw of our Series so SQL raw series just like that so essentially whatever this series is my generate series I&#39;m going to be taking each individual value from that series and I&#39;m going to be putting it through the exact same date grouper so converting it to a date or a month and so on then what I&#39;m going to do I&#39;m going to call this map with function taking in my date string I&#39;m going to pass it to my interval. dat formatter and that&#39;s going to take in a new date based on my date string there we go so what this little bit of code right here does map width essentially says okay after my SQL code runs how do you want me to convert this SQL to JavaScript so I&#39;m saying hey take this date which is a string and convert it into an actual date object for me from here I can finish out the rest of my code by making my joins and stuff work properly for example for my group grouping I want to group based on whatever that date is and that&#39;s because I&#39;m truncating all of my different date information down to either the month or the week or so on so when I do my left join I&#39;m taking whatever my visited at right here is and I&#39;m going to be truncating that based on my date grouper so here put in that date grouper that&#39;s going to truncate down my date and here I want to get my date and this comes from the function version of this so I can take in the date just like this call this function which is going to call just like that there we go so essentially I&#39;m getting that date row which is right here from my database that date column and I&#39;m comparing okay if I truncate my date that comes from here it should be equal to this date here I know this is very complicated SQL code but essentially what&#39;s happening is in this first subquery I&#39;m getting all of my products that I have access to and I&#39;m counting up all the views for each individual visit that I have actually I&#39;m not even counting them I&#39;m just combining together my products and my visited ad and then inside of here I&#39;m saying okay give me a series of data that&#39;s going to either months or days and convert all my visited at times to either that month or that day and if the day for the visited at and my series are equal add one to my count and do that for every single Row in this first query so now we can see if this actually worked I can come in here comment all of this information in make sure we pass our props in just like that import this particular function and now we just need to add this chart in which again shouldn&#39;t be too difficult we can just copy one of our existing charts this particular chart here is going to be by date and actually I believe I called this by day so let me just clean that up a little bit there we go views by day this is going to have date information so I&#39;m going to have a date and that&#39;s going to be a string because it&#39;s whatever I mapped that to that&#39;s converting that to a string for me and then all I need to do is instead of my country code this should be my date and everything else should just work out of the box so let&#39;s see if that&#39;s working we can come in here get my chart information and then I can open this up and you can see all of my views were on the 16th that&#39;s why you can see we have 12 visitors on that particular day which it means that it&#39;s working and we have all these blank days which is great if we didn&#39;t generate that series of data we would just have one row or one column in this chart and all these other columns wouldn&#39;t show up because they would get no data but by doing that series it now gives us these blank days the last thing we have left to do is just add in all of our different filtering that we want to do so we can go all the way back to our analytics page all the complex charting stuff we&#39;re done with that we can just close that down the only thing we have left to do is filtering which is so much easier so the very first thing I need to do is I need to wrap this entire thing inside of a div just my H1 section just like that that way I can put my filters up here with it and I want to add some margin on the bottom we&#39;ve been waiting for this for a long time they&#39;ve been really pushed together Flex this with some justifying of between to push them as far away as possible and items Baseline just like that there we go so now inside of here I&#39;m going to put a giant has permission and I only want to have these things show up if I have permission to access the analytics so if I can access the analytics then go ahead and show the content inside of here which is going to be a div with a class of flex and a gap of two and then we just need a bunch of drop- down menus so we&#39;re going to get some drop down menus just like this I&#39;m going to have a dropdown menu trigger just like that this is going to have an as child because it&#39;s just going to render out a button and this button is going to be a variant of out line inside of here interval. Lael is what we want to render and we want to render that with a Chevron down so we know that it&#39;s actually something that we can click on and go down on so we&#39;ll say class name size 4 margin left two close that off and we should see hopefully there we go we have last seven days right there obviously it doesn&#39;t do anything else we just have the drop down trigger so let&#39;s go ahead and add the drop down content drop down menu content there we go so this is for changing between our different intervals so we need to Loop through all of our different intervals so we can say object. entries for each one of our chart intervals I want to map through them that&#39;s going to give me a key and a value and then I want to return essentially just a link but that&#39;s going to be inside of a drop-down menu item there we go close that off make sure we say that this is as child and it has a key which is our key now for each one of these I&#39;m going to be creating a link make sure that&#39;s a next link we&#39;re going to add in an href here which I&#39;m going to come back to what it&#39;s going to be it&#39;s a little bit of a complicated href but otherwise we&#39;re going to have our value. Lael inside of here just like that make sure we close all this off there we go give that a save looks like everything&#39;s working our drop down menu content I believe we made not have imported so let me make sure I import that there we go and that should actually work now our href we&#39;ll just make an empty string for now so this will render hopefully there we go and now you can see we have our different options obviously it&#39;s not quite looking as we expect though most likely I imported my drop- down menu item from the wrong place which I did so let&#39;s clean that up and now you can see we have our different intervals showing up but the links currently don&#39;t work so to make the links work I&#39;m going to create a little bit of a helper function we&#39;ll just close down these function it&#39;s going to be called create URL and this create URL function is going to take an href which is a string it&#39;s going to take take some old params which are our old parameters that are search prams so that&#39;s a record of the string string type and then finally it&#39;s going to take some new prams which is again just a record of strings so there we go record string string and this is going to return to us an href now I&#39;m actually going to move this into our lib folder so we&#39;re going to go into lib utils I&#39;m going to paste that down into here now for this particular function it&#39;s not going to be too complicated first our prams is just going to say new URL search prams and we&#39;re going to pass in all of our old parameters then what we&#39;re going to do is we&#39;re going to Loop through all of our new parameters by saying object. entries with our new parameters we want to Loop through each one of them so we&#39;re going to get a key and a value and for each key and value all I want to do is that the value is equal to undefined then I want to remove it so prams do delete that key otherwise what I want to do is say prams do set the key to that specific value then finally I can return what the brand new href is going to be so we say href with a question mark and p.2 string now we can generate a brand new URL anywhere we need to so for example back on this particular page where I have my link I can just say create URL I can pass it in the URL that I want to go to which is SL dashboardanalytics and what I want to do is pass in my old search prams and I want to change the new pram for my interval to be whatever this particular value is actually in our case I want the key and let&#39;s just import this function whoops create URL looks like it&#39;s not automatically importing probably because I forgot to export it there we go now let&#39;s make sure we import this give that a save and now hopefully if I click last 30 days you can see up here it&#39;s changed to last 30 days and my chart has updated if I change to last 365 you can see again it&#39;s updated my URL and the important thing is you can see it&#39;s rendering out each individual month which is exactly what what I wanted back to last 7 days you can see that&#39;s updating this chart as well so we have our very first drop down menu done the next one we want to work on is our product drop down and I&#39;m actually just going to bring this into its own component and make a little bit easier to work with so we&#39;ll say user ID is our user ID our selected product ID is equal to our product ID and our search prams is equal to our search prams close that off we&#39;ll just need to create this function down here again I have the typing for my parameters already in there because that&#39;s some pretty basic stuff and I want to get my products so we can say await get products get products there we go for my user ID and then we can return inside of here all the different drop down stuff we need so I might as well just copy this drop- down menu paste it down because it&#39;s going to be rather similar to what we had before except for here I&#39;m going to be getting my individual product and looping through my products and so on so this is going to Loop through my products and here I&#39;m going to have an individual product product just like that and then up here for my actual label this is going to be a little bit of a complex thing so I want to take my products and I want to find the product with the specific ID I already have so p. ID is equal to selected product ID and I want to get the name from that and if the name doesn&#39;t exist I&#39;ll just have it say all products there we go then the next thing I need to do down here is I first want to create a link specifically for all of my products so drop down menu item add as child and inside of here is a link that goes to my analytics page using my old search prams and it sets my product ID to undefined by completely removing that type now I do need to make sure that this can include undefined so that I can actually remove things now if I go back to here that got rid of that error and this just removes product ID from my URL now down here I want to Loop through each of my products the key is going to be my product. ID just like that for my href I want to use my product ID and set it to my product. ID and down here this is my product. name now if I give that a save that should hopefully clean up all our errors and now I have the ability to say okay give me it only for this product or for all my products now if I create a brand new product just give it a random name random URL equiv that a quick save this product has absolutely nothing associated with it at all as you can see it also looks like my tab is currently incorrect I need to fix that so let&#39;s do that real quick before I forget we&#39;re going to go into our page for our products we&#39;re going to go to our edit page and all the way at the top where we have our tabs being defined you can see this is called country not countries so I&#39;ll change that to countries and that will actually fix it now when I go to the page you can see it&#39;s on that country Tab and there we go it&#39;s on the country tab that actually fixed all that okay back to analytics so now I have three products test name three has data this one has no data so as you can see all these are blank no data available down there and for all products we see all the data for all of them combined together together now the very last thing that we need to implement is the time zone drop down and this is something that a lot of charting places don&#39;t do and I really wish they would because it&#39;s super useful to be able to choose things in your own specific time zone so copy this drop down menu down this one&#39;s going to be very simple right here we&#39;re going to render out whatever the time zone is there we go that&#39;s our current time zone and we don&#39;t even need to do any type of array looping or anything like that we just need our drop- down menu item we don&#39;t even need a key on it because we only have two different options we have UTC and we have non UTC so for the time zone we have UTC just like that and inside of here we&#39;re going to print out the text UTC so that&#39;s going to be our UTC option now we need to add the option for our current time zone and this will actually require us to create a brand new component and that&#39;s because we need it to render on the client because otherwise it&#39;ll give us whatever our server&#39;s time zone is so we&#39;re going to get the drop down menu item which is going to take in our search pams there we go and now let&#39;s create this component so over into here we can just go into our components create a brand new file call it time zone drop down menu item export function that exact item right there this is going to be taking in our search pams whoops search pams and this is going to be search pams this is a record which is string or string there we go and then all we need to do is just render out this drop down menu item I&#39;m just going to copy the code because it&#39;s relatively straightforward and I&#39;ll explain it we just getting our drop down menu item we&#39;re making sure we render it as a child because we want to render a link inside of it we&#39;re creating a URL just like we did for the rest of them the only key difference is that we&#39;re actually getting whatever the user&#39;s current time zone in right here so I&#39;m just going to take this and say const const user time zone is equal to that and then we can just place that in both sections there we go this is the user local time zone so now here I can import this and we should hopefully see if all this loads that I now have the option to view my data in UTC or in my current time zone which is the America Chicago time zone now it currently makes absolutely no difference but I&#39;ll show you a case where it actually would make a difference we&#39;ll say npx run DB Studio there we go and actually I don&#39;t need the npx I should just say npm run DB Studio that&#39;ll open up my drizal studio I&#39;m going to add a brand new piece of information into this we&#39;ll just make it full screen we&#39;ll go over to our product views and I&#39;m going to add a brand new row for this particular product ID this particular country ID and for the date here I want to just do 202 24-09-2019 now what I can do is close out of this and go back to my application here give page a refresh and you&#39;ll see that we should hopefully have some visits on that particular day let&#39;s go to UTC make sure it&#39;s all products give that a quick refresh it&#39;s actually showing up on the 16th even if we&#39;re in our time zone here it&#39;s still showing up on the 16th and I&#39;m almost 100% sure the reason for that is because of our caching obviously manually changing our database doesn&#39;t reset our cach so to easily reset our cach I&#39;m just going to refresh this page that&#39;ll add a new product View and that should fix our cash in immediate you can see if I switch over to UTC I have a date on the 15th but my time zone is before UTC so when I switch to my time zone you can see that that date that was at midnight UTC actually swaps to the day before so this is why it&#39;s really important to be able to show people&#39;s data in UTC or their current time zone cuz for me this was something that happened on the 14th while if I look at it in UTC it looks like it happened on the 15th now that pretty much is everything we need to cover but I actually realized I forgot to do something way back all the way on our dashboard page I never added any additional for our most popular to add like a little Banner in the corner which is something that we should have so what we can do is we can actually go back to that particular page in our marketing page that&#39;s going to be our normal page and what I want to do is all the way at the very bottom inside of my pricing card I have the ability to see which one is most popular you can see is most popular and I want to add quite a bit of additional flare to this if it is the most popular one so in particular on my card I want to add quite a bit of additional class names so here I&#39;m going to have CN to do all the class name stuff and and I want to have it be relative I want to have a shadow of none I want to have it be rounded 3XL overflow hidden and then what I can do is if it is the most popular I can add additional classes so I can say that my border should be the accent border and I&#39;ll put a border of two around it otherwise I&#39;ll have a border of none there we go so now my most popular one you can see has this nice big blue border around it which looks good already ready the next thing I want to do is directly inside my card header if it is the most popular then what I want to do is I want to render out a little Banner that&#39;s going to go in the top left of the or the top right of the card so we&#39;ll say class name background is going to be accent text is accent foreground we&#39;re going to make sure that it&#39;s positioned absolutely padding on the top and bottom is going to be one padding on left and right is going to be quite large at 10 we&#39;re going to position negative right in the 8 top is going to be 24 and we&#39;re going to rotate this 45° and I&#39;m also going to set the origin to be in the top right and this is just going to say most popular and what that&#39;s going to do is add this little Banner most popular across the very top right corner of this particular card another thing I realized I completely forgot to add which would break your application when you deploy it to production is if we go all the way into our API open up that API for our products remember how I told you that this request object is going to have information for our actual user this request. Geo in our get country code if I open this up this request. Geo that only is the case on versell if you have your runtime set to Edge otherwise that will not work so make sure you have a runtime set to Edge another thing I didn&#39;t really do is if we go back to our dashboard here and we look at our main dashboard you can see we only have the product section we don&#39;t have anything for analytics we should probably add that in as well so let&#39;s go to our dashboard our main page and let&#39;s add in a section for analytics it&#39;s going to look pretty much identical to this H2 section up here so I&#39;m going to copy that over it says analytics it has that arrow to the right with all the same Styles and then I&#39;m obviously not going to show anything unless the person has permission to access the analytics and if they do we&#39;re going to show them this analytics chart now this analytics chart is just the exact same as our day chart so we&#39;re going to get all of our day chart information let me make sure this a little bit bigger so it&#39;s easier to see so you can see get views by day chart data we&#39;re passing in our user ID and our interval and we also need to pass it in our time zone which in our case is going to be UTC let&#39;s get our chart interval because this is going to show for the last 30 days because it kind of shows them the last month which is good indicator of how their application is doing and then as you can see that this card is literally exactly the same as the card we had before so all of this is pretty much the same as what we&#39;ve rendered before but now you can see we&#39;ve rendered out all of our products and if I zoom this out a little bit more you can see we now also have our analytics for the last 30 days if I click on this it brings me to my analytics page another minor thing I realized I forgot to do is in our product customization form if we scroll all the way down for our location message actually that was all the way at the top I went too far we look inside of here here I never actually put the error message in here so let&#39;s make sure we have that form message showing up and with that final minor change that is absolutely everything we need for this full application to be completely built and honestly this is a massive application if you put this on your portfolio employers are going to love it and even if you don&#39;t it&#39;s a project that you can build and sell and actually make money from and if you want you can view all the source code in the description down below again a huge thank you to Clerk and neon for sponsoring this video because of them I&#39;m able to actually create these massive projects entire for free for you I wouldn&#39;t be able to do that without their support So if you liked Clerk or neon from this video I highly recommend checking it out they&#39;ll be linked down in the description for you with that said thank you very much for watching and have a good day
Here are ranges for the difficulty score:
0.0 - Absolute Beginner: The content uses very simple vocabulary and basic phrases, with clear visuals and context. Ideal for someone who knows no target language at all.
0.1 - Beginner: Simple sentences and common vocabulary. The video may include some visual aids and context to help understanding.
0.2 - Low Beginner: Slightly more complex sentences, but still uses everyday vocabulary. May introduce some basic grammar concepts.
0.3 - Intermediate Beginner: A mix of simple and slightly more complex vocabulary. Some industry-specific terms may be introduced, but they are explained.
0.4 - Intermediate: More complex sentences and a broader vocabulary. Some idiomatic expressions may be used, requiring a bit more background knowledge.
0.5 - Upper Intermediate: The content includes industry-specific vocabulary and concepts. Viewers should have a good grasp of the target language to fully understand.
0.6 - Advanced: The video uses advanced vocabulary and complex sentence structures. It may include nuanced discussions that require a strong command of the language.
0.7 - Very Advanced: The content is aimed at fluent speakers, with specialized terminology and concepts that may not be familiar to all native speakers.
0.8 - Expert: The video is designed for professionals in a specific field, using highly specialized language and concepts that require extensive knowledge of the subject matter.
0.9 - Educated Native Speaker: The content is sophisticated, with advanced vocabulary, idiomatic expressions, and cultural references that assume a deep understanding of the language and context.