Full Stack Spotify Clone: Next 13.4, React, Stripe, Supabase, PostgreSQL, Tailwind (2023)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there my name is Antonio and welcome to this comprehensive tutorial where we'll take you on an exciting journey to recreate one of the world's most popular music streaming services a Spotify clone in this video we'll guide you to the process of creating a fully functional and aesthetically pleasing music platform using the most powerful and modern web development Technologies we'll kick things off with next 13 making use of its new app router to efficiently manage routing and dynamic page rendering we'll dive into react for creating interactive user interfaces and crafting reusable components that will form the backbone of our application when it comes to design we'll Leverage The Power of Tailwind CSS and red X UI will assist us in building a Sleek modern and responsive user interface on the database side we'll be working with Superbass and postgresql to create a robust and scalable data storage solution capable of handling a multitude of users songs playlists and much more we'll also be focusing on creating Advanced authentication we'll cover forgot password functionality custom email templates magic links and social login options for user convenience and enhanced security we will also guide you through the process of MP3 song and image upload using Super Bass storage providing users with the ability to customize their songs last but certainly not least we'll integrate a payment getaway for monthly subscription handling using stripe this will allow users to opt for premium features and a seamless payment process so put on your developer hat and get ready to immerse yourself in this Rich tutorial let's create a Spotify clone that Rivals the best in the music streaming industry on top of all of that our website is going to be fully responsive and in the end I'm going to show you how to deploy all of that on Virtual so let's get started and let's configure our next 13 application go ahead and open your terminal either in your vs code or in a separate window and run the following command npx create next Dash app at latest and before you press enter make sure you put the name of the folder where you're going to develop your application in my case it's going to be Spotify clone like this and press enter after that you're gonna get prompted with a couple of questions for the typescript select yes for sland option select yes for Tailwind CSS select yes as well for the source directory select no for the app router select yes if you want to change the default import Alias you can do that but I recommend you press no on this option so you use the same code that I'm going to write and just wait a couple of seconds for all of this to install great after this has been installed you're gonna get a message with a success and the folder name where this has been initialized so I'm going to go ahead and I'm going to click open here and I'm going to select the Spotify clone folder like that and right here you should have a structure very similar if not exactly the same as mine so we have the app folder this time without the API folder in previous versions or previous tutorials you might have seen that we also got an API folder but now that does not exist by default we have to create one if we need one in the future we also have the globals.css file with some predefined Styles the layout the TSX with some metadata a predefined font and we have the page DSX with our welcome screen so without further Ado let's go back into our terminal and that's actually run this application so we can see what's actually going on in order to run a next 13 application all you have to do is write npm run Dev and press enter and that is going to start a server on localhost 3000 so go ahead in your browser and you can just refresh like this and I'm just going to zoom out a little bit so you can see uh so I can see exactly what you see on this desktop version a new next 13 welcome screen like that great now what I want to do is I want to remove all of that because we are not going to need it for our project so I'm going to go back and make sure you're in your page.tsx file inside the app folder like this and we're going to remove everything inside of this return function here so start with the main and find where it ends and you can just go ahead and remove it and instead of that you can just write a div with a Hello Spotify like this and you should have a completely different text here right now so the only thing visible on the localhost 3000 should be hello Spotify like this great and while we are here in this page.dsx you can also remove this import for the image because we're not going to use it in home great and what I want to do next is I want to go into globals.css right here and I want to remove everything inside except the Tailwind direct apps because we gonna need those so go ahead and remove everything like this just leave the Tailwind directives and that should change your background to White if it was already white that is because of the color scheme that you're using in your computer so no worries about that great and while we are in this globals.css file I want to add a couple of styles so let's go ahead and let's write HTML comma body comma root and just write height 100 percent background color black and color scheme dark like this and that should turn our screen back to black exactly as we want it for our Spotify clone perfect and one more thing I want to change is I want to go into tailwind.config.js file right here and I want to remove everything inside of this extend object because we are not going to need that so just go ahead and remove everything like this so your theme object should have an extend object which is completely empty because we are not going to use any of those files great and what we're going to do now is we're gonna go back into our layout.tsx file inside the app folder and I'm going to replace the inter font with a fixed refund so go ahead and just write victory like this and replace the enter with fig tree like that the constant should not be named enter anymore instead you can just name it font and make sure you replace the body class name font that class name as well and you should see a very slight font change in our localhost 3000 here which is a bit more similar to what Spotify uses and before we wrap this up let's also change the title in this layout metadata to Spotify clone and a description to listen to music like that and now if you take a look at your tab it should have the new title of Spotify clone like this perfect now let's go ahead and let's go into our page.dsx right here and let's try a class name here so I'm going to give this a class name of text green 500 and if your Tailwind has been configured successfully you should see a new Green version of your text right now just make sure you actually save your changes right here now if you're wondering how come I'm seeing this green little box at the end of my class and how come when I hover I can see the exact CSS inside for that you're going to use an extension called Tailwind intellisense so just go into your extensions and click on the first Tailwind result and make sure you install that and Beyond the seeing the CSS and the colors you can also see some autocomplete functions right here so make sure you install that extensions each is very useful When developing with Tailwind CSS great before we wrap it up I just want to modify our structure a little bit so I don't want to use the page that DSX inside the root of the app folder I want to create another folder inside of it but I don't want to change the route so what I'm going to do right now is I'm going to go back into my terminal and just make sure you shut down your application to avoid any problems when doing this we're only going to do this once so go ahead and shut down your application and refresh your localhost and make sure it says this site cannot be reached to ensure that it's not running and now what I'm gonna do is I'm going to create a new folder inside of this app folder called parenthesis site so it's very important that you put this inside parenthesis so they don't create another route and now what you're going to do is you're just gonna copy and paste the page.tsx file inside and then you can remove this old page.ts X like this great so the only page of the DSX file which you're going to have is the one in the parenthesis site folder like this and you can change hello Spotify to Hello site like this and now let's go ahead and just run this in the terminal again just make sure you removed the old page.dsx which was in the app folder so the only page that vsx you should have is the one in the parenthesis site folder and just run npm run Dev again and refresh your page and you should see uh the very same text right here so hello site like that perfect and if you change it back to hello Spotify again everything should work just fine great so we successfully uh finished setting up our environment in the next board we're gonna start working on our layout on our sidebar and some other items great great job so far so let's go ahead and let's create our sidebar component which is going to wrap our main content here so first thing I want to do is I want to change this hello Spotify again to main content because that's what's going to be our main content so I just want to point that out right here great and now I want to go and I'm going to close everything and inside of our root folder here so not inside app folder I'm going to create a new folder called components like this great and inside I'm going to create a new file called the sidebar the DSX like this let's go ahead and let's name it sidebar like this and for now all it's going to do is it's going to render children like this in order to fix this typescript error we have to create an interface sidebar props like this which accepts children which is a type of react.react node like this and then we have to assign this so react.fc sidebar props and then in the parentheses you can just extract children like this perfect and now what we're gonna do is we're gonna go into our app folder into layout.dsx and we're going to wrap our children with that newly created sidebar component so go ahead and write sidebar and just wrap the children like this and you can indent it if you want to and you can import sidebar from add slash components slash sidebar because we just created that component right here and if you save nothing much should change so we're gonna go ahead and improve that now so go back into your sidebar component here and first thing I want to mark this as you use a client because our cyber component is going to be dynamic so don't worry this is not this will not mean that every single thing inside of our sidebar will also become a client component because we are passing them as children so this is the proper way to pass server components inside a client component but we do need this sidebar component to be a client component because we're going to do some Dynamic stuff here so first things first let's add a hook here const path name is equal use path name and you can import use path name from react sorry next slash navigation like this I'm just gonna expand my screen a little bit like this great and besides path name we're also going to create an array of possible routes in our project so go ahead and write const routes is equal use memo you can import use Memo from react like this go ahead and just return an empty array and don't forget the dependency array like this great and inside of this array you can go ahead and open it we're going to add a first object which is going to have a label of home like this it's going to have an active prop which is going to compare the current path name which we just imported here using this path name Hook and the home navigation is going to be active every time we are not on slash search so we're going to have a very simple navigation in this project so that's why we don't have to compare it with Slash home for example we are going to use it we're going to make it active every time the path name is not a search great and the href is going to be slash great and the second object we're gonna have is going to have a label of search active is going to be path name is equal to slash search and href is going to be slash search like this so now that means that we have to add this path name to the list of our dependency arrays right here and before we continue I also want to add an icon to each of these navigation objects so go ahead into your terminal I'm going to shut down the app and write npm install react Dash icons like this wait a couple of seconds and you can run the app again and if you've shut down your app make sure you refresh it after you run it again otherwise you're not gonna see your changes uh in real time great and the icon I want to add here is hi home like this and you can import hi home like this AJ home from react icon slash hi like that perfect and for the search I'm gonna use an icon of bi search like this and make sure you import that from react Dash icons slash bi like this perfect and what I'm going to do now is I'm going to modify this div a little bit so I'm going to remove the children from now and I'm just going to write sidebar like this so now only sidebar should be visible here great and let's give this div a class name of Plex and H dash pool all right nothing much should change now remove this sidebar and inside create a div with the following class names this is going to have a class name of hidden now this is very important make sure you're not accidentally in mobile view so make sure that you're not that your browser is not too small expand it a little bit so it ensures that it is on desktop view the reason I'm telling you this is because we're going to work mobile first as you can see I just added a hidden class here which means display none but the second class I'm gonna ask I'm going to add is MD Flex meaning on medium screens it's not going to be hidden it's going to be Flex so if you're developing on a mobile screen you're not going to be able to see the changes that we're doing right now so make sure you expand or zoom out your screen a little bit even though nothing's happening right now uh you're gonna notice uh things very soon all right besides mdflex we're also going to add Flex Dash call Gap Dash y-2 BG Dash black H dash full W Dash square brackets 300 pixels p dash 2 like that great now inside of this we're going to create a box component so go ahead and just write box like this and for now you can just write uh sidebar navigation like this and if you save you're gonna get an error because box does not exist so let's go ahead and let's go into our components folder and create a new file box that TSX like that and let's just quickly write box like this and what I want to do is create a div which is going to accept children like this so let's quickly create an interface box props which accepts children react dot react node like this and it also accepts a class name which is an optional string like this now let's assign this so react.fc box props like that and now you can extract children and class name like that perfect and now go back into sidebar.dsx and you can import box from uh dot slash box like this because they are in the same folder in the components folder here great and now let's go back into box so we can focus a bit more here so before we continue we have to install another package called the Tailwind merge so go ahead and go into your terminal here I'm gonna shut down the application and write MP install Tailwind Dash merge like this I'm just going to expand my screen a little bit and there we go npm install Tailwind Dash merge and just press enter on that one and npm run Dev again and refresh your page uh if you've modified it so if you shut down your application and run it again great and now I'm going to give this a class name open curly brackets TV merge like that TW merge sorry and we're gonna import TW merge from Tailwind Dash merge like this great and now go ahead and open parenthesis here and you can either use normal strings and write classes inside of here but because I want to collapse them for a tutorial in multiple lines I'm going to use backticks so choose what you like and inside of here I'm going to write BG Dash neutral 900 you can see how I got a small little effect right here great a rounded LG H dash fit and W Dash full like this great and after this last thick or in your case it might be a normal annotation string I'm going to add a comma like this and I'm just going to pass in last name so what I've done here is I've enabled us to reuse this box component and to pass in some additional class names if we want to do so great so that finishes our box component here so let's go back into our sidebar here and I'm gonna add uh I'm gonna copy this box one more time like this and this second one is not going to be navigation it's going to be our song Library like this and I'm gonna show you how this class name that we just passed works so I can now modify the class name and I'm going to write overflow Dash Y dash Auto and H dash full and you can see how that box fills the entire screen that we have here uh great that looks great and now what I want to do is uh I want to modify at this sidebar navigation to actually display this route right here so what I'm gonna do is I'm going to remove sidebar navigation text from here I'm going to open a div I'm going to give you the class name of flex Flex Dash call GAC Dash Y dash 4 px-5 and py-4 like this and inside I'm going to open curly brackets and write routes dot map item and I'm going to immediately return a new component which we're going to create sidebar item like this and I'm going to give it a prop key of item.label and the rest I'm going to spread like this and if you save you're gonna get an error because cyber item is not defined so let's go into our components and create a new file sidebar item with ESX like this let's just quickly fix this sidebar item hey div sidebar item like that go back into sidebar.dsx and just import that from dot slash cyber item the same way you did box and you can see how we now have two instances of the text sidebar item that's because we iterate over this routes array right here and we render the same text every single time a great so now what I want to do is I wanna modify this sidebar item so it actually does something useful so let's go back into sidebar item here and first things first let's create an interface so interface sidebar Island crops like that we're going to use an icon which is a type of Icon type which you can import uh from react icons so I'm just going to go ahead and import icon type from react Dash icons like this we're also going to have a label which is a type of string an active which is an optional Boolean and an hret which is a type of string and now let's assign these props to react.fc is sidebar item props like that and now you can just extract all of those so icon label active and href great now instead of using div I'm going to use a link component and you can import this link component from next slash link like this and the required property that link component has is hrefs go ahead and immediately pass in the href like that great and the other thing we're going to do is we're going to write a class name so go ahead and instead of using strings we're going to use a curly bracket because we're going to use the W merge again so go ahead and just import a TW emerged from Tailwind Dash merge like this go ahead and open door emphasis again you can use normal annotation strings but for the sake of the tutorial I'm going to use backdicks so I can collapse my classes I'm going to give it a flex Flex Dash row H dash Auto items Dash Center wool Gap Dash x-4 tax Dash MD font Dash medium cursor Dash pointer hover text White transition text Dash neutral Dash 400 py-1 like this so now you can see if I hover you can see how I have a nice little effect here great and now I'm going to add a comma at the end of my back tick here and I'm just going to pass in active and end text Dash white so you can see how my first item is active by default that is because in my routes array right here I gave it an active prop every time we are not on slash search and since we are certainly not on slash search in our localhost that means that the first item is active great so go back into cyber item now and one thing I want to do is I want to remap this icon prop to an icon with a capital I so we can use it as an element so go ahead and write it like this great and I'm going to remove this sidebar item here and I'm going to write icon like this with the size of 26 and you can see how now I have two icons at home and a search icon and below that I'm gonna add a paragraph and I'm going to render the label inside of that and I'm going to give it a class name of truncate and the W Dash 100 like this sorry blue like this great and now you can see how we have a working example of our navigation sidebar items great great now before we create our library component here um I just want to find a way to render children using our sidebar because if you go into our app folder into layout you can see that we've wrapped the children but right now the children are not rendering anywhere so let's go ahead and fix that let's go into our sidebar component find the last div right here and write a main element at the bottom like that and inside we're going to render our children so you can see how my main content just appeared here I'm going to zoom in just a little bit so it's a bit more visible and I'm gonna give this a class name of H dash full flex-1 overflow Dash Y dash Auto and py-2 like that great so now it's just a little bit more aligned to the rest of our structure perfect so now instead of having a song Library here I'm gonna have an actual component called Library like that and if we save of course we get an error because the library is not defined so let's go ahead and fix that I'm gonna go into my components folder and create a new file Library the TSX like that it's going to be a client component so let's write use client at the top it's going to be named library and I'm going to quickly fix this error by just writing Library like that now I'm going to go back into my sidebar component and I'm just going to import this from dot slash Library like that perfect now let's go ahead and let's create a empty little function here const on click and for now it's not going to do anything but I'm gonna write a comment handle upload later because we're going to use this on click to open an upload model uh which we are going to use to add our songs great now I'm going to remove the library text from here and I'm going to give this a class name of flex Flex slash hole like that I'm going to create another div inside the with the following class names so class name is going to be Flex item slash Center justify Dash between px-5 pt-4 like that now inside of that I'm going to create another div and I'm going to give this one uh a class name of inline Dash Flex items Dash Center and GAP Dash x dash two like that great and inside of that if I'm gonna add an icon TB playlist like this and I'm going to import TB playlist from react Dash icons slash TV like this and if I save you can see how I have a small little icon here great now what I want to do is I want to give this a size of 26 like this so it looks just a little bit larger and I also want to give it a class name of tax Dash neutral Dash 400 like this so it's a little bit muted a little bit more gray a great and now just below this playlist icon I want to open a paragraph and write your library like this and now let's go ahead and let's just style this a little bit so I want to give it a class name of text Dash neutral Dash 400 font Dash medium and tax Dash MD like this so it looks just a little bit better great now just outside of this div right here I'm gonna write an icon AI outline plus like this and you can import AI outline plus from react icons as well so from react Dash icon slash AI like that great and you can see how I have a nice little plus icon here now let's go ahead and let's give it some attributes so on click it's gonna open our own click method which we defined in the beginning which currently does nothing but in the future it's going to open a subscription model uh sorry it's going to open an upload song model uh let's give it a size of 20 and a class name of the following tax Dash neutral Dash 400 cursor Dash pointer over text Dash white and transition like this great so now uh let's just fix this so neutral like that make sure you don't misspell the text Dash neutral Dash 400. so now you can see when I hover I have a nice little effect that our element is applicable uh great and now just outside of this div right here open another div and give it a class name of the following Flex Flex Dash call Gap Dash y-2 mt-4 and px-3 and for now all I'm gonna write here is list of songs like this great so that uh sums up our sidebar uh now we're gonna focus on creating a main comp main content a bit more better uh basically what we've done in the sidebar is created the basic layout which we're going to need and later on we're going to go back here to add some functionality to all of these items right here so now let's go uh and I'm gonna close everything here I'm gonna go into my app folder into site into page.tsx right here and what I'm going to do here is I'm gonna remove this main content text for now and what I'm gonna write instead is I'm going to modify this class name a little bit so instead inside I'm going to write the following classes BG Dash neutral Dash 900 rounded LG H dash full W Dash full overflow Dash hidden and overflow Dash Y dash Auto like that perfect so you can see how now our content also has a similar element um sorry a similar element to our sidebar great now inside of that we're going to use a new component which we did not have until now Heather and for now I'm gonna write uh is header inside and if we say we're going to get an error because header component does not exist so let's go into our components folder header the PSX let's just quickly fix this so header like this I'm going to return a div hello Heather look at that go back into page.tsx and you can just import this from add slash components slash header and if you save the error should go away but we're still going to have this typescript error because we have not defined the props for the header component so let's go ahead and let's do that here so inside I'm going to create an interface header props it's going to accept children which is a type of react.react node and a class name which is an optional string so very similar to what we did to the Box component and now let's assign these props right here other props like that and inside you can extract children and class name like this perfect great and now I'm going to add a router here so use router makes you import it from next slash navigation like this great and I'm also going to add another empty function here honest handle log out which for now is not going to do anything but I'm just going to write handle log out in the future like this just fix the typo here all right and now I'm going to remove this text right here uh and yes we have an error because we used use router inside a server component so make sure you mark our header component as use client like this great now the error should go away go ahead and write a class name here open curly brackets TV merge which you can import from Tailwind merge like this great open parenthesis here and I'm going to use backticks again I'm going to write H dash fit BG Dash gradient Dash 2 Dash B which means the bottom ROM Dash Emerald Dash 800 p dash six like this and you can see how my main content now got a nice little Emerald gradient effect here perfect and after this last tick I'm just gonna pass in the class name prop like that perfect now inside of this go ahead and open a div and give it the following class names so it's going to have W full mb-4 Plex items Dash Center justify Dash between like that and inside of that create another div component and give it a class name hidden and the blacks Gap Dash X-2 and items Dash Center so while you're developing this it's very important that your sidebar is visible if it's not visible that means that you're on a mobile view and you're not going to see what we're gonna develop now so make sure that at least your sidebar is visible like this so you can expand it as much as you can but just make sure the sidebar is visible great and now inside of that what we're going to do is we're going to write a button element like this and inside I'm gonna put in the RX current left icon and you can import RX card left from react Dash icon slash RX like this and if I save you can see how I got a nice little icon here so I'm just gonna zoom out a tiny bit more so you can see uh more clearly great let's give this RX card left a size of 35 like this so it looks a bit better great and let's give it a class name of text Dash white like this all right and now let's go ahead and assign some class names to this button so class name is going to be rounded Dash full BG Dash black s items Dash Center justify Dash Center cursor sorry we don't need cursor Dash pointer so hover opacity Dash 75 like this and transition like that great so now if you try and hover on this element you can see how it has a nice little effect here so what I'm going to do now is I'm going to copy this entire button and paste it just below that and let's see how we now have two elements here but for this one I'm going to use RX call it right and you can import that in here the same way you did with RX card left perfect and now on the first button I want to give it an on click which is an arrow function which is going to call router.back and the other one you can copy this again and give it the other one here it's going to use router.forward so we're going to use this as our personal forward and backwards inside the application uh great great job and if you try and collapse this you can see how on mobile view we're not going to see that because on mobile view we're going to replace these little icons with our navigation for home and search great so we're gonna do that now so go ahead and find the end of this last button and find the end of the div that surrounds it and below that open another div like that and we're going to give this div a class name of Plex and the hidden Gap Dash X-2 and items Dash Center so what's important When developing this part is that you actually go into mobile view so make sure that your sidebar and your navigation disappears because you can see by default on mobile this is going to be visible but on medium is going to be hidden so make sure that you are in mobile view so you can see what we are going to be developing right now I'm going to go ahead and write a button element inside again and I'm going to use an icon hi home like that and you can import hi home from react icons as well so import AJ home from react Dash icon hi like this great and inside of that after I save this you can see how I have a nice little home element here let's give this a class name of text Dash black and the size of 20 like this it looks a bit larger and now let's go ahead and assign some class names to this button and of wrapping the hi home elements great so let's give it a rounded Dash full B-2 BG Dash white Flex items Dash Center justify Dash Center cursor sorry again we don't need cursor because it's already a button element hover opacity Dash 75 and transition like this great and you can see how on mobile we now have a nice little home button here so you can go ahead and copy this entire button and paste it just below itself and now you're gonna have two icons for this one we're not going to use hi home but bi search like this and you can go ahead and import that as well so import bi search from react icon slash bi like that perfect so now we have two nice little elements here and if you try and expand you can see how it disappears on desktop but on mobile it's visible that's exactly what we want what we're going to do now is we're going to build our button component which we're going to reuse here for login and sign up elements so let's go ahead and find the end of the last button which is only visible on mobile and then find the end of its enclosing div and just below that go ahead and open another div and go ahead and give it the following class names so class name is going to be equal to flex justify Dash between items Dash Center and gap-x-4 like this great now inside of that I'm going to write an empty fragment like here and I advise you that you do the same it might not make sense right now but in the future we're gonna make this content be dynamic depending on whether we are logged in or not so I just want to prepare for that in the future now go ahead and open a div and inside of that go ahead and write eight button elements but this time it's going to be a different type of button it's going to be our custom button so if you save the file you're going to get an error that button is not defined make sure you're written it with a capital B and not with the lowercase b like that so let's go into our components and create a new file button the TSX like this I'm just going to quickly fix our error the button like that I'm going to go back into header component I'm going to import button from dot slash button like this and you can see how it's on the right side of here and it should also be visible on mobile as well but for now it's not looking like a button instead it's just showing a text here great so I just want to prepare for this so I'm going to go into my header component I'm going to find this button right here and instead of a self-closing tag it's going to be a normal closing element like this and inside I'm going to write sign up like that great now let's go into our button.us X and that's actually uh add some attributes here so we're going to create a special type of component here we're going to pass the ref and we're going to create a smarter interface here so instead of custom instead of writing each prop that button can accept one by one we're just going to use the attributes that react provides us so go ahead and write interface button props extends react dot button HTML attributes open pointy brackets and write HTML button element and just write an empty object at the end like this great and now I'm going to remove everything here and I'm going to write just cons button here and it's going to be equal to forward ref which you can import from react like this before we move on I just want to write the button dot display name is going to be equal to button like this right now we have an error for that but don't worry it's all going to make sense uh in a second go ahead and open pointy brackets here and write HTML button element and the second prop is going to be button props like that uh great and now go ahead and open uh uh parenthesis here go ahead and open another parenthesis and open an object inside like this and here we're going to extract last name we're going to extract children we're going to extract disabled and we're going to add a type which by default is going to be button like this and the rest is going to be props like that and outside of this curling bracket we're gonna also extract a rough and now write an arrow function open a function and just write return a plain old button element like this great so basically what we've done here is we've created this nice little way of forwarding our ref and forwarding all the attributes the normal HTML button has without uh without usually writing it you can see how in header we had to write children and class name but for this button we just extended the regular HTML attributes which the button has great so what I want to do now is I want to give this a type of type like this a class name is going to be TW merge again and we can go ahead and import DW merge from Tailwind merge like this go ahead and open parenthesis again I'm going to use backticks and I'm going to write w Dash ooh rounded Dash full and also I'm just going to render children inside so you can see what we're working here with here uh you can choose whether you want to do this on desktop view or mobile view I'm just going to expand a bit so you can see more of my code here but focus on this sign up button because this is where the styling is going to change as we write it so by default I'm going to use BG Dash green Dash 500 order border Dash transparent px-3 py-3 disabled cursor Dash not Dash allowed disabled opacity dash 50 text Dash black on dash bold however capacity Dash 75 and transition like that and at the end after my last tick I'm just going to pass in class name like this so we can always modify our button if needed that now after class time I'm also going to pass in the disabled prop and a ref graph like that and I'm gonna pass in the rest of the props like that perfect so that wraps up our button component now we can safely go back into our header right here go ahead and find where we use that body component so there we go I wrote a sign up button right here and I'm gonna give it a different class name here so I want to show you how we can reuse our button component and also modify it to look completely different so it's going to have a BG Dash transparent backslash neutral Dash 300 and font Dash medium like this and you can see how now it looks completely different I'm also going to expand this to desktop view so you can see how our sign up button looks right now uh great so I'm going to copy this entire div wrapping the button I'm gonna paste it here again and instead of sign up this time it's going to be login and it's going to be a bit of a different uh last name for this one so what I'm going to use here is BG Dash white px-6 and py-2 so you can see how my login button looks a bit different here great and I'm just going to prepare the on click here so I'm going to give it an empty Arrow function like that and you can go ahead and copy that and give it this button here as well in the future it's going to open our our login models great so I think this looks amazing uh if you collapse and because at the desktop you you can see that it's still visible uh in the same way uh great so what I have to do now is I have to find a way to pass children from our header because in page you can see that our header is wrapping and having some children inside and we're gonna pass these children is right here at the end of our div like this and you can see how our header now appears right here great so now we're gonna go ahead and start developing that part so let's go back into page.tsx where we wrote the header so inside of our parenthesis site folder right here and instead of having the plain old text header we can actually go ahead and add some divs and some H1 elements so go ahead and write the div last name mb-2 go ahead and open an H1 element and write welcome back like this and you can see how we have a nice little welcome back text here but I want to give it some Styles so let's go ahead and give it class name text Dash white text-3 Excel and font dot semi bold and now it looks a bit closer to what Spotify has great now just below that I want to open another div right here and I'm gonna give this a the following class names so class name is gonna have grid whoops grid grid Dash whole slash one SM grid Dash course Dash 2 XL grid Dash course Dash three to excel grid Dash course Dash four like that Gap Dash three and empty Dash four like that perfect and inside of that I'm going to create a new component called list item so I'm gonna write list item like this and if we save we're gonna get an error because a list item is not defined so let's go ahead and resolve that let's go back into our components folder and create a new file list item that is sex like this let's go ahead and quickly fix this so list item div list item like that and let's go back into page.tsx and just import it from add slash components slash list item and the error should go away and you should see the text list item here now let's go inside this list item and what we're going to do is we're going to add the interface first but before we do that let's also Mark this as a use client because it's going to be an interactive component go ahead and write interface list item props image which is a type of string name with the type of string as well href which is a type of string and go ahead and assign this so react.fc list item props like that and you can extract all of those so image name and href like that perfect now what I want to do is I want to get our router here so use router make sure you import it from next slash navigation not next slash router because it might autocomplete for that make sure you use next slash navigation because in next 13 that's what we're going to use execute the hooks you actually have a working router here and I'm gonna prepare my own click here so const on click is a arrow function which for now all it's going to do is a router that push to whatever href we're gonna pass here in the future but I'm going to add a comment here add authentication before push so I only want the users to be able to visit this if they're authenticated in the future great now instead of having this list item div I'm actually going to have a button so go ahead and write a button not our custom button we're gonna actually use the regular button element here and let's go ahead uh and let's give this a class name of the following relative group blacks item slash Center rounded Dash MD overflow Dash hidden gap-x-4 BG Dash neutral Dash 100 10 like this cursor sorry no need for cursor pointer however BG Dash neutral 100 20. transition and PR Dash or like this great and now what I want to do is I actually want to create another div inside of that and I want to give it a class name of the following relative Min Dash H dash square brackets 64 pixels below that Min Dash W open square brackets 64 pixels as well and what I'm going to use inside is an image element uh from next slash image like this if you save you're gonna get an error because or maybe you won't get an error okay great we don't get an error here but what we have to do is we have to pass the image prop from our list item but we do not have that yet so I just want to prepare you for that what we're going to do is I you can either find an image on Google that you like which we are going to use for your liked playlist or you can go into my repository right here so I have it right here I'm just going to zoom out a little bit and you can go into the public folder into images and find light.png that I have right here and you can just download it and after you've downloaded the file go ahead into your public folder and create a new folder images and drag and drop the light inside of that and make sure you rename it to light.png because it needs to be like that PNG otherwise it's not going to work great so I just want to prepare for this and I'm gonna go back into page.tsx now and you can see how we already have a typescript error because it's missing some props but for now I'm just going to give it an image of Slash Images slash like that PNG so it needs to be the exact path here images folder that's why I'm writing images and like that PNG because that's the exact name of this file great and now we can go back into list item and we can actually pass in some attributes to this image element which we imported from next slash image here so go ahead and give this a class name of object dash cover I'm going to go back into my localhost here and I'm just going to close this all right I'm going to give it the property fill source is going to be image and all is going to be image and you can see how our uh light image nicely fills this area right here a great and now just uh below this div which wraps our image I'm gonna go ahead and open a paragraph and I'm going to render a name inside of it you're not going to see anything now so let's go back into page.dsx and let's give this a name of like songs like this so now we can actually see how it says like songs actually I want to use the capital S like this it looks a bit better and let's also give it an href of light like this great and now we have all the props we need here and we can continue developing in our list item here so I want to edit this paragraph a little bit so let's go ahead and give this a class name of font medium rank 8 and py dash 5 like this great and just below that I'm gonna go ahead and create another div here and I'm going to give this a class name for now I'm Gonna Leave it empty because I want to show uh I want to show you what I want to put inside here first and that is an fa play icon like this so go ahead and import that from react icons so import fa play from react Dash icons slash fa like this and you can see how now you have this nice little play icon here so go ahead and give this a class name of text Dash black like this it's going to make sense in a minute when we add these class names here so go ahead and give this a class name of absolute transition opacity Dash zero so now it's going to disappear rounded Dash full blacks items Dash Center justify Dash Center BG Dash green Dash 500 p dash 4 drop Dash Shadow Dash ND write Dash five group Dash hover opacity 100 and hover scale 110 like this so now you can see when I hover on this light songs element I have a nice little play button and when I hover on it again it scales so I just want to explain how this works and why this works so if it's not working for you make sure that you put the relative class name in your main parent button and make sure you also put the group class name in your main parent element right here so the way group works is that we Mark group as our parent element and then here we use the group hover and a effect that we want so Tailwind now knows that wherever I hover on this parrot element I'm going to create an effect for this child element right here which holds our play button here and how we position it in this area exactly well for that we added a relative class name to our parent and then we use an absolute positioning on our child so we are able to use write-5 to just move it to the exact spot that we want a great great job and I just want to wrap this up by adding just a couple of more elements here so go back into page.dsx whoops before we do that go back to the list item and let's go ahead and use this on click in this button here let's not forget to do that so on click on click like that perfect go back into page.tsx right here and where the header ends go ahead and open another div with the class name of empty-2 mb-7 npx-6 like that and inside of that go ahead and open another class name here with a flex Justified Dash between and items Dash Center like that and inside of that just go ahead and create another element H1 with newest a song's title like this great I'm just gonna collapse this inside so it's a bit more readable for you and I'm gonna give this a class name of text Dash white text Dash to Excel and font semi bold like this and now it looks a bit better great and just below this uh div right here uh I just I'm gonna open another div and write list of songs like this so in the future we're actually going to create some new elements here in some new components which are going to render uh individual cards of our songs great uh you racked up the entire layout which we're gonna need uh for our uh project uh now we're gonna start with actually creating some authentication so we can create some models and then we're gonna uh also configure our Super Bass and our database and we're gonna start uploading some songs great great job so far uh you created a lot of reusable components and you've learned how to style with the Tailwind great great job you can play around with how this looks you can see how nicely respond responsive this is on all devices and how it changes the grid depending on the size of the screen great great job so we're going to continue and in this part of the tutorial we're gonna create and set up our database using Super Bass so in order to do that go into Google and write Super Bass or take a look at my description in the video and you will find the Super Bass URL it should be the first result in Google so super based the open source Firebase alternative go ahead and click that and create an account here I already have an account so I'm going to click sign in and I'm going to use continue with GitHub because I created an account using GitHub so you just go ahead and sign up using whatever method you want it does not matter and once you are logged in you're gonna see a dashboard similar to this so what I'm going to do now is first I'm going to acknowledge that I already have a couple of organizations here and a couple of projects here so you probably have a bit of a different view than I do but that does not matter uh if it's asking you to create an organization feel free to do that just create an organization make sure it's public and give it whatever ever name you want and what I'm going to do now is and what you should do is find a button which says new project so wherever you want go ahead and just click new project and choose an organization where you want to put your project into so I'm going to select code with Antonio it does not matter what organization you use for the name of my project I'm going to give you the name of Spotify Dash clone like this for the database password it has to be a strong password I suggest you click this generate a password button right here and make sure you copy the password and save it somewhere so for now all I'm gonna do is I'm going to create a new file here and I'm gonna name it password the txt like this and I'm just gonna paste it here so I don't forget it make sure you don't accidentally commit this in your database so what I want to do now is I want to go to dot git ignore right here and I'm just going to add password the txt like this so your password is not accidentally committed uh to your GitHub so make sure you do not share this with anyone after I upload this video I'm actually going to remove this entire project so this password isn't going to matter so just be very careful when saving this password you can you can save it anywhere you want just don't lose it great and if you did this password the txt file the same way I did make sure you went into git ignore and just put that file inside so it's not accidentally committed to GitHub great now that you have your password for the region you can leave whatever is selected and for the pricing plan make sure you select the free option zero dollars a month and just click create a new project like this so I'm going to expand this a little bit and let's just wait a couple of seconds for all of this uh to set up uh great so now you can see how we have the project API Keys here we have the uh public key and we have the service role and we have our URL so while we are here I actually want to use all of this and add it to our environment file so I'm going to go back into my code here and I'm going to create a new file called dot env.local like this and by default dot envy.local is in git ignore meaning that it will not be pushed to your repository which is exactly what you want you never want to commit your environment files the same way we did with password.txt I just want to make sure so this password.txt you don't need that in your project so I only wrote this because it's useful to save your password somewhere but you don't have to do it you can save your password wherever you want on your mobile phone send an email to yourself write a text message WhatsApp whatever you want but this dot environment.local you need this file so create dot environment.local here and in order to go back to see where your API options are if you got redirected like I did just click the little Cog button here for project settings and click on the API like this and we're going to need a couple of environment attributes here so I'm going to write them out now but what I suggest you do is you go into my repository and take a look at the dot environment dot example where you can see exactly which Keys we are going to need and I also wrote a comment where you can find all of this settings great so these are obviously stripe which we are going to need in the future but for now we're going to focus on this three so the first one we need is next underscore public underscore Super Bass underscore URL the second one is next underscore public underscore Super Bass and on key and the last one is Super Bass service role key like this great so just save this dot environment.local file and double check from my repository that she didn't accidentally make a mistake here so you just copy and paste them like this so you confirm that they are correct great and now we can go back into API settings here and for the first environment variable the next public supervised URL you can go ahead and copy your project URL like this and just paste it here for the next public Super Bass add-on key for that you just have to copy this add-on public key right here so go ahead and copy that and paste it and for the Super Bass Service roll key it's exactly this the service role so click reveal and then click copy and just paste it here great so we have all the environment variables we are going to need for our Super Bass and now I just want to do a couple of uh just a quick show around of Super Bass and how great it actually is so you can see you can choose to create tables and rows in many ways you can use the table editor you can use the SQL editor you can see your entire database here with web hooks triggers and functions and you have a separate tab for authentication so superbase is really great because it offers you to send an invitation to user from its dashboard you can also see in the future when we have some users in our project you will be able to send them a reset password email a magic link remove the user uh block the user a bunch of stuff is available and you can also change email templates so this is what our email is going to look like once the user registers in our project this is the email that's going to be sent to the user if you want to add an image for your project or your company here feel free to do that so you can play around with this if you want to and you also have the variables here great you can also change the The Heading and you can also see a bunch of different email templates that we have here and we also have the providers so you can enable the phone provider you can enable the Apple Azure bitbucket Discord Facebook a bunch of providers here so that's how powerful super bass is I think this is very useful to us and we also have the storage which we are going to use later to upload our songs and images to great and you also have Edge functions but we're not going to use that for now so before you create your first user Make sure you did not create any users so just leave this empty and go and click into the SQL editor here and you can see how useful this is so we can either write a new query from scratch if you know SQL you can do that or you can use a little help from this pre-made script if you want to create table just click here you want to create a column just click here or you can scroll all the way to the bottom and you can find this quick start scripts you can create a country script a slack clone script a to-do list script or in our case stripe subscriptions so go ahead click on this SQL editor here scroll all the way to the bottom and find striped subscriptions so this is a starter template for next JS stripe subscriptions starter exactly what we need so just click here and here you can see the exact script which we are going to run in our project uh sorry in our database which is going to create all these tables and rows and relations and some triggers and some functions but one thing I want to notice I want to tell you so if you don't have if you by accident don't have this stripe subscriptions even though I don't know why you wouldn't have it but maybe if in the future Super Bass decides to remove this for some reason I copy the script and you can go into my Repository and you can find database.sql file and it's the exact same script that I copied here so you can just copy that and paste it instead of using this uh quick start if you don't have it but I do have it so I'm going to click stripe subscriptions here and I'm just going to quickly go uh over what this is going to do so first we're going to create a table users with an ID full name outer URL billing address and payment method and then we're going to add some row level Securities here so that only the logged in user who is the owner of that user can view its own data and only the user can update its own data no one else can do that we will also create a trigger here that every time we register a new user a new user will be inserted into our custom users table right here that's what this part does then we're going to create some stripe required tables which is customers products pricing types so these are some types we have pricing types pricing intervals uh we're going to create a table table prices right here with all of the needed uh attributes for stripe uh we're also gonna uh alter the row level security the same way we did from users we're gonna create a subscription status uh type right here so these are all the possible types from stripe so you can see how much this quick start script helps us usually we'd have to write all of this ourselves but this quick chart is really amazing again if you don't have it it's exactly the same what I have in my repository in database.sql right here great so you can take a look at this if you're a bit more interested into exactly what this is but as I said the only Uh custom one actually uh is this users everything that you see here customers the products the pricing the types the subscription status all of that is required for stripe and it is tailored to stripe API and what it needs great and you can see how it's commented very well so you can take a look at it and see exactly what you need great so after you're satisfied with this make sure you did not accidentally alter anything just go ahead and press run and after that it's going to write success no rows returned great and now go and click in the table editor here and you can see how we have customers table and for you can see that we have an ID and a stripe customer ID the price is stable and in here we're going to have all the attributes which were written in that script that prices need to have same thing for products for subscriptions and for users and in all of these tables we also have the active RLS policies great so that's pretty much all we need for stripe what we're gonna do now is we're gonna create some custom tables which we're going to need for our Spotify clone those tables are going to be a song stable and a Light song stable so kind of like a playlist so so I'm gonna go ahead and do that now so go ahead and go into your table editor here and click new table or you can click create a new table here and the first table which we are going to create is going to be songs so just go ahead and write songs here leave this as it is so enable a row level security we're going to have to create some policies and now what we have to do is add some columns here so you can see I have predefined ID which is a type of integer and a created ad which is a type of timestamp with the time zone and it is a selected that this ID is my primary key so that's exactly what I want and what we're going to do now is we're just going to add a couple of more columns here so go ahead and click add column and the First Column we're going to add is title and that title is going to be a type just go ahead and find text so variable length character string like this and by default it's not going to be anything great then add another column and this one is going to be song underscore path like this yes and it's also going to be a type of text below that add another column which is going to be called image path so go ahead and write image underscore path like this also a type of text and uh now we're gonna add uh the author so go ahead and add a column called author like this which is also going to be a type of text and another column which is going to be called user underscore ID so it's going to be the person who uploaded this song user underscore ID and what you're going to do for that is you're going to click this edit foreign key relation button right here select the public schema find the users and select the ID from users like this and for the action go ahead and write Cascade like that and just click save great and you can see how that automatically filled the type of this user ID column to uuid like this perfect so go ahead and just click save and wait a couple of seconds and it's going to create a completely new table with seven columns that we just added so ID created add title song path image path author and user ID and there we go you can see how we now have uh our songs table here but very important this songs table will actually not be usable at the moment because we have no active RLS policies so go ahead and click on this no active RLS policies right here and click on new policy right here and again uh Super Bass offers us some templates right here so you can write it yourself or you can just click get started quickly create a policy from template so the first thing we're going to do is we're going to write enable read access to everyone so go ahead and click use this template and uh you can write uh so go ahead and write select like this uh sorry I'm just going to close this a little bit and my bad I removed it so go ahead and click new policy again get started enable read access to anyone select leave this to true so don't don't click on anything like I did and just click review right here and you can see the policy that's going to be created here and just click save policy like this and now you should have a new policy here enable read access for all users we're going to need another policy along that which is the enable insert for authenticated users only so we only want to enable a logged in users to add new songs but we want all users to be able to load them in their browser so go ahead and click new policy again get started quickly and we already did the first one so now we want the second one enable insert access for authenticated users only don't change anything here click use template don't touch anything here so you can see how it's selected authenticated Target role here and just click review like this and you can see uh the policy which is going to be inserted so go ahead and click save policy like that perfect and now you can go ahead and go back into table editor into songs and you can see how we have two active RLS policies right here which are the enable insert for authenticated users only and enable read access for all users perfect and now we're going to create uh one more table which we are going to need and that is going to be our liked songs table so go ahead and click new table the name is going to be liked songs so I'm just going to zoom in a little bit so you can see like that again leave the RLS security here leave the uh instead of this ID so you can go ahead and uncheck this ID right now so we're not going to have a primary row here instead instead of an ID we're going to write user underscore ID and you can click on this edit foreign key relation go ahead and find the users and select the ID and the action is going to be Cascade and click save and you can see how that filled our user ID so you go ahead and add another column song underscore ID for that you can go ahead and click edit foreign key relation again and select your newly created songs table and it's going to automatically select the ID and the action is going to be Cascade and click save and now we need to have a primary key you can see this warning right here so go ahead and select the user ID and the song ID so those two are going to be our composite primary key and you can leave the created at so we can order them by newest in our project and go ahead and click save like that and again just wait a couple of seconds and that is going to create a the like the songs table with three very simple columns great and again right now it's not usable because we don't have any active RLS policies so again click here and go ahead and click on new policies first thing we're going to do is add the enable read access to everyone so just click use this template don't touch anything here and click review and save policy like this great now go ahead and add a new policy again get started quickly right here enable insert access to authenticated users only use this template don't touch anything review and save policy like that and we're also going to need a third policy here to enable only those users who added something for them to be able to remove that so again click get started quickly and we're going to enable delete access for users based on their user ID so only the owner of this table row is going to be able to delete it great so just click review and save policies so this one should have three policies just like that perfect and that is actually it for our entire database schema so we have everything we need here and what I want to do now is I want to go into storage and we're going to create two buckets which we're going to use uh to upload our songs and our images so go ahead and click new bucket here and the first one is going to be songs like this and go ahead and click on public bucket like this because it's going to be simpler to develop with for now and if you want to you can do some additional configuration here if you want to restrict file upload uh and if you want to restrict it to specific um to specific Domine type so for example in these songs what I'm going to do is I'm going to allow only audio slash MPEG like this so audio slash MPEG or you can just leave it empty if you want to so but just make sure it's audio slash npg or empty nothing else because we are going to upload MP3 three files not any other type of file and go ahead and click save like this great and what we're going to do now is we're going to create another bucket called images and you can just go ahead and Mark it as public bucket again and click save like this great and now go ahead and go into your policies here and what we're going to do here is create a new policy for songs again get started quickly uh and what we're going to uh what we're gonna write here is we're just gonna enable a bunch of these policies right here but instead of using these templates that we did for now I actually want to go back so go ahead and click on new policy here and click uh for full customization like this it's going to be easier to actually write it like that so give this policy a name allow all like this and just go ahead and select all of this like that and just click review and save policy like that perfect so now we allowed all of uh the policies for songs it's going to be much simpler uh develop to develop that way and what I want you to do is I want you to do the same thing for images so go ahead and write in your policy for for full custom customization right allow all and select select insert update and delete and don't do anything for the Target roles click review and save policy like this there we go so now our public bucket is much easier to develop and we're not going to have any trouble uploading images and retrieving them from the same great so that is actually it from our database to wrap up make sure you have the customers the like songs prices products songs subscriptions and users and make sure you added the two RLS policies to our songs table which are the enable insert for authenticated users only and make sure you in our in your light songs you have the three active RLS policies for the lead insert and select and in your storage we've written some custom policies where we allowed everything from everyone because it's going to be simpler and just to show you a little bit how you can write custom policies and not use templates great great job so that is actually going to be it for our Spotify sorry for our Super Bass uh configuration here I advise that you leave this tab open so you can actively monitor what's going on in your database and what we're going to do next is you're actually gonna go ahead and create some providers and we're actually gonna go ahead and add the login functionality all right so what I want to do now is I actually want to generate the types from our database because you can see we have a bunch of types here A bunch of tables a bunch of rows and I want to use typescript in my project so I don't want to type everything myself I want to use a script which is going to generate all of the types from our database and assign it in our project so the way I'm going to do that is I'm going to follow this guide from Super based documentation I'm going to put this into the description but don't worry we're going to do this together so I'm just going to collapse everything here right here I'm going to zoom in just a tiny bit more so you can see what we're going to run so let's go into our terminal here I'm going to shut down my application and what I'm going to do is first I'm going to install super bass as a Dev dependency here it's important that it is at least a 1.8 version so go ahead and write npm install super bass at open parenthesis greater than equal 1.8.1 and dash dash save dash dash Dev like this so basically this thing right here I'm just going to expand so you can see it in the terminal as well and press enter like that and wait a couple of seconds for this to install great now that that is done we're gonna run the following command MPX Super Bass login so to prepare for that go into your uh dashboard here and go into project settings right here and now we're going to write MPX Super Bass login like this and you can see how uh it prompts us to enter our access token and it shows us an URL where we can generate our tokens so you can go ahead and control click on this so it's going to open it in your browser right here so I'm just going to click again continue with GitHub so I'm logged in and I'm gonna get redirected to my tokens page or so you can just either copy this URL or control click on it and you will get to your access tokens and you can see right here I have my access token so what I'm gonna do here is I'm actually just going to either generate a new one or copy this one so just a couple of seconds here go ahead and click generate a new token here and provide the name so I'm going to write a name Spotify Dash clone Dash CLI like this the name pretty much doesn't matter and just click generate a token like this and wait a couple of seconds and there we go uh so make sure that once you generate this token copy it because if you refresh the page you're not going to be able to access it again and once you've copied it just go ahead and paste it here you're not going to see anything when you paste so just press enter after that and you can see it says finished super bass login like that perfect and now what I'm going to do is I'm going to go back here and see the next step so now we're going to use the MPX Superbus gen I mean generate types typescript and we're going to have to prepare our project ID here in advance so let's go ahead and let's go here and let's find our project ID so your project ID is your reference ID in the settings right here so go ahead and find your reference ID and copy it to prepare it great and now we're gonna go ahead and run the following command so it's going to be a tiny bit different than this one because we're not going to put it in this file right here we're going to put it in a different file so go ahead and write mbx Super Bass gen types typescript dash dash project Dash ID and now just go ahead and make sure you've copied your reference ID from here okay so I'm just going to zoom out a bit so copy your reference ID here like that and then just paste it and then I'm going to write dash dash schema Dash public like this and I'm gonna go back here just to see schema public open the grader at sign and just write types underscore db.ds like this and press enter and I made a mistake so uh the mistake was that I wrote schema Dash public so that does not exist so I'm just going to expand this a little bit let's clear this again and we're going to write the same thing so npx super bass generate types typescript dash dash project ID make sure you've pasted your project ID and instead of Dash their schema Dash public just go ahead and write public like this and make sure you insert that in types underscore db.ts like that and just press enter like this and there we go now it works and now you can see how I have a new file types dot DB right here in my project and you can see this is our entire database here so that is going to help us a lot with type safety if you had any problems uh doing this so if you didn't manage to create your typesdb.es file you can always go into my repository and find it here so types underscore db.ds and then you can just copy it and paste it if your project since you are doing the exact same database that I am great so I made a small mistake with schema Dash public make sure you don't do that and I repeated my steps so it should work for you as well great so that's how we created our types and now we're going to use this interface database when assigning our providers which we're going to do in the next part so now we're gonna go ahead and we're going to create a couple of providers in our project so let's go ahead and let's create a new file sorry new folder here called providers like this and inside of this provider create a new file called superbase provider.psx like that so make sure its name is super based provider like that and if you want to you can start your application if you haven't already so go ahead and run mpm run Dev right here and refresh your logo host to make sure that it is working nicely great and in here first we're going to mark it as use client after that we're going to import database from ads types slash underscore DB so the file we created in the previous part great and now I'm going to write interface superbase provider props like this it's going to accept children which is a type of react.react node like this great and now just write const Super Bass provider is equal to react.fc Super Bass provider props and go ahead and extract the children right here and open an arrow function like that so what I'm going to do next is I'm gonna actually install a couple of packages which we need to continue so go ahead and open your terminal here and I'm going to shut down my application you don't have to if you don't want to and go ahead and run npm install at Super Bass slash out Dash helpers slash next JS like this so go ahead and just install that with a couple of seconds for you to complete and then we have to install uh the equivalent package for react so after that's done go ahead and install npm install at Super Bass slash out Dash helpers Dash react like this so just wait a couple of seconds for that to install as well and then you can go ahead and npm run Dev your project one more time great and I just want to show you in my package Json which versions of that I have so these are the dependencies I've just installed and these are the versions I'm using great so what we're gonna do next is we're actually going to create a state here so go ahead and write cons uper bass client is equal to use state which you can import from react like this I'm just going to separate this Imports like that and go ahead and open an arrow function inside which is going to uh just write create browser uh Super Bass client so create browser super base client like that from Super Bass dash out helpers next JS like that and just give it a type of database like this and execute the function like that and as you can see uh this is actually deprecated so I just did a quick Google search and I don't want to give you a deprecated version of that so we're actually going to import a different version so instead of create browser Super Bass client we're going to import create client component client like that and that's what we're going to use here like that perfect and make sure you just assign the database here and great and now our super based client as you can see has all of our database types so sorry for that misunderstanding with create client browser component great so now that we have that we're actually going to go ahead and just return session context provider from Super Bass Alf helpers react right here so make sure you import that as well and give it a super based client of Super Bass client like this and inside we're going to render our children like that great and I just want to separate the imports from our custom Imports like that so what we've done uh is we installed these two packages right here we imported create client component client so my apologies again I accidentally imported the create browser Super Bass client which is outdated for now so this is the up-to-date version for next 13 app router you can technically use the older one still so it's still available even though it's deprecated but the version that I put at the first which was crossed out is actually going to be deprecated and removed in the future great so now that we have this super based client make sure you write export default super based provider at the end like here and now uh what I want you to do is I want you to go into layout so go ahead into your app folder into layout that's the SX and I want you to wrap the sidebar with Super Bass provider like this so just go ahead and wrap everything inside like that great so now we have the access to client Super Bass inside of our application perfect what I want to do next is I want to create a use user hook which is going to be very useful to us because we're also going to store subscription uh status in there so go ahead and I'm just going to expand this a little bit and create a new folder called hooks so go ahead and a folder hooks like this and inside you're going to go ahead and create a new file use user.tsx like this and great so first let's go ahead and let's actually create another file in the root of our application called types so the same way we did with types underscore DB we're actually going to create a manual one types dot DS like this so these are going to be our custom types which we are going to need so in this case we're going to need to prepare uh a couple of uh uh types here so before I continue let's go ahead and let's shut down the application and let's run npm install stripe like this so we can use the types from stripe and just run Dev again and refresh your page here so import Stripe from stripe like this and now first I want to import the uh first I want to create the user details here so let's go ahead and write export interface user details like this it's going to have an ID which is a type of string a first underscore name which is a type of string last underscore name which is a type of string as well full underscore name which is a type of string and full name is also going to be optional like this Avatar underscore URL is an optional type of string so this is going to be assigned if we're using oauth billing underscore address which is an optional stripe dot address like this and payment underscore method is going to be optional and stripe dot payment method like that stripe Dot payment method DOT type like this great so besides the user details we are also going to need the subscription types so go ahead and write export interface subscription this is going to be an ID of string user ID of string as well status which is going to be a story status which is going to be an optional stripe dot subscription dot status like that we're going to have metadata so optional stripe dot metadata like this uh we're gonna have price underscore ID which is an optional string quantity an optional string as well cancel underscore at underscore period underscore end question mark Boolean like that created string like this print underscore period underscore start string print underscore period underscore and string as well uh ended underscore add which is going to be optional string like this cancel underscore add is going to be an optional string as well and I'm just going to scroll this up a little bit cancel at so uh yes we're gonna have cancel add and cancel that string so this is some stripe specific uh Fields that's why maybe they don't make sense but they are important for stripe and trial underscore start string trial underscore and string and prices price uh like this and we obviously also have to create a price Model now so let's go ahead and let's do that so let's go ahead and write export interface price and uh what price is going to have uh is an ID of string product underscore ID which is an optional string active an optional Boolean uh description is going to be an optional string unit underscore amount is going to be an optional number currency is going to be an optional string type it's going to be an optional stripe dot price that type like this interval is going to be an optional stripe that price that recurring that interval like that interval underscore count uh is going to be optional number trial underscore period underscore days question mark is going to be a number or null like this and metadata is going to be uh stripe that metadata also optional and products this is going to be product like this so now let's go ahead and let's export interface product so this is going to have an ID of string active which is an optional Boolean name which is an optional string description which is an optional string as well image which is an optional string and metadata which is an optional stripe dot metadata like this great so we created a couple of a a couple of uh interfaces here which we're going to need uh for start we are also going to create uh some more later on uh but for now this is what we need uh for our use user hook right here so let's go back to the use user hook and let's uh actually write our context type so go ahead and write type user context type like this access token is going to be a string or null like this user is going to be a type of a user which you can import from out helpers next JS like this or is going to be null like this user details is going to be user details which we just created in the types like that or null as well is loading it's going to be a Boolean like that subscription is going to be subscription which we just created in the types as well or null like this so I just want to separate this Imports like that great so we have the type user context type right here and now let's actually create the context so export const user context is equal to create context which you can import from react like this the type is going to be user context type or undefined that angle has an open parenthesis and by default it's going to be undefined like that perfect now let's go ahead and write the props interface so export interface props is gonna have a prop name which is a type of string and it can be any so we just created like a general props here great now let's actually go ahead and write the uh my user context provider so go ahead and write export const my user context provider like that let's give it a type of props of props and let's go ahead and let's extract a couple of things from this session context which we can now use because we wrapped our entire application in Super Bass provider so let's go ahead and write const is equal to use session context like this and you can import use session context uh from out helpers react like this so I'm just going to move this to the top as well and the items we are going to extract from here is session is loading uh and we're going to remap that there is loading user like this we're going to have super based client which we're going to remap to Super Bass like that uh great so that's all we're gonna need from the user session context and now we're gonna get uh the user from Super Bass so go ahead and write const user is equal to use super user now you cannot import this from anywhere because it's not uh defined like that so what we're actually going to do is we're going to go into our out helpers react right here and I'm going to import use user as use super user like this so we have the use session context and we have the use user as use super user so why am I remapping this well because our use user is going to be our custom hook so that's what we're working in we're working in a file called use user so that's how we're going to name our hook so I just don't want to create any conflicts so that's why we remap it to use super user like this great so now that we have the user let's go ahead and let's access our token so const access token is equal to session question mark access underscore token like this and just use this double question mark null like that great now let's add a state is loading data set is loading data like that use state which you can import from react right here and give it the default value of false like that and below that we're going to assign a state for our user details so const user details set user details is equal to use State like that and by default is going to be null and the type that is going to have inside the US states so open pointy brackets like this and write user details or null like that perfect now below that go ahead and write a subscription and set subscription use state by default is going to be null and the type of use state is going to be subscription or null like this so this is going to be a very useful hook because we're going to use it to load user details and to load the subscription so we can reuse this hook wherever we want and we can quickly check whether the user has an active subscription or generally if we are authenticated or not so that's why it's going to be so useful and why we are doing this so now let's write two actions which are going to use super bass to actually fetch uh something from our database so let's go ahead and write const get user details is equal to superbase that from users like this dot select put an asterisk inside dot single like this great so now we're gonna get our user details perfect and now write const get subscription you can write it all in one line I'm just gonna collapse it so Super Bass from subscriptions select we're going to put an Asterix and now we're going to also fill our relations so the way we do that is we pick a relation we want to field in our case prices and open parenthesis again and we're going to select everything from prices and I also want to select another relation inside of prices so I'm going to write comma products and I'm going to select everything inside so just make sure that you have the parentheses for the prices and parentheses for products as well great and we're gonna only select a specific subscription type so in status go ahead and open an array of trialling and active like this great n dot single at the end like that great so now we have a function to call our user details and to call our subscription perfect so now let's write a news effect which is going to patch this information and assign it to this state right here so use effect like this go ahead and just put a dependency array here and first let's check if user and and is not loading data and and we have no user details and we have no subscription so if we are logged in but we are not currently loading and we have not loaded the user details and we have not loaded the current description in that case set is loading data the true because we're going to start loading some information so go ahead and write promise dot all settled like that and open parenthesis and open an array and give it a function of get user details which we just created comma get subscription like this perfect and then write dot then and inside uh we're gonna open an arrow function with results like this and just open another arrow function inside and just write const user details promise is equal to results zero like that and const subscription promise is equal to results one like that so our first uh our user details we're going to fetch from a get user details so that's going to be the first item in the array and our subscription details are going to come from the second item in this array so that's why we use the first the zero and one from this array like that great now let's just check if user details promise that status is equal to fulfilled like that in that case I'm gonna set user details to user details promise that value dot data as user details like that great now I'm going to write if subscription promise dot status is equal to fulfilled as well in that case we're gonna set subscription to subscription promise dot value.data as subscription like that perfect and after that we're just going to write set is loading set is loading data to false like this perfect and now what I'm gonna write is go to the end of this first if Clause that we've written else if there is no user and we are not uploading user and we are not loading data in that case we're just going to reset everything so set user details null and set subscription to now as well and in the dependency array we are only going to put user and is loading user like this so yes we're going to get a warning but you can ignore that for now otherwise it's going to cause a lot of refreshing that we do not need great so what I'm gonna do now is I want to create a value constant here so go const value is equal to access token user user details is loading which is either going to be it's going to be a combination so it's loading user pipe pipe is is loading data like this and subscription at the end like that perfect so now we have that value and now what we're going to do is write return uh user context dot provider like this it's a self-closing tag and we're going to give it the value of value and we're also going to spread any props from there as well like that great so we have finished creating our provider now this was a lot of code it was a bit complicated so what I advise you to do if you think you uh you might have made a mistake here or just want to double check you can always go into my repository right here and you can go into my hooks right here into use user and you can see the exact code that is written here so you can double check if something went wrong the only thing that's different here uh is that uh sorry now nothing is different here so just feel free to use it exactly like this great all right so I'm going to expand this again and let's actually create our hook so export const use user like this const context is equal use context which you can import from react right here in this context pass in the user context like that if context is equal to undefined so if you're trying to use this hook outside of our context in that case we're going to throw a new error uh use user must be used within a my user context provider like that perfect otherwise just return context like this great so this is going to be a very very useful hook for us uh where we can we are going to be able to fetch our subscriptions and our user details at the same time so what I want to do now is I want to create another provider so go into your providers folder and create a user provider that the SX which is going to be very very simple so mark it as use client like this uh write an interface user provider props like this children react.react node like that and just const user provider react.fc it's going to be a type of user provider props like that go ahead and extract the children and return my user context Provider from at hooks use user which we just created and just passing the children inside like that and expert default user provider like this perfect so now what I want to do is I want to go back into my app folder into layout.dsx and inside Super Bass provider so important very important inside the supervised provider go ahead and add a user provider which we have in our providers use user provider we just created it a second ago like this and wrap the sidebar within it perfect great great job so this is going to help us a lot we are now ready to start developing our authentication model and to check whether we are logged in or not if we made a mistake anywhere we're going to find that out along the way so no worries if you if you test yourself now and see that something's not working if you try to use this hook don't worry just continue with the tutorial if I notice something's not working we're gonna fix that together great great job so far so we're going to continue and we're going to create a provider for our models and then we're going to create a model component which later we are going to turn into a our first functioning model which will be the authentication model where users can log in create a new account reset their password and send magic links so let's go ahead and let's go into our providers folder where we have the superbase provider and user provider and create a new file model provider.dsx like this go ahead and Mark it as use client like that and just a write model provider for the component name and the export and what we're going to return for now is just going to be an empty fragment right now which is going to say models like this great and now let's go ahead and add some states here and some other functions so const is mounted set is mounted it's going to be equal to use State false like this and you can import use state from react like that and we're gonna do a simple trick which is going to prevent any errors being caused by our models since we are doing server-side rendering here models can cause hydration errors so in order to prevent that we never want to render a model if we are in server side rendering so this is how we're going to do that I'm going to create a used effect here which is going to change this is mounted to True once it's loaded so if this use effect ever loads that means we are already on the client and we can safely show our models so go ahead and write set is mounted to True like that perfect and now I'm going to use an if Clause here so if is mounted sorry if uh exclamation point is mounted like that return now like this perfect so basically what's going on here um we are ensuring as I said we are ensuring that none of the models can be seen or opened during server-side rendering and this is a little trick that we can use so that if we notice that we are in so this is the equivalent of us knowing hey whatever is being rendered right now is in server side so just return no for that otherwise we're going to add all of our models here later when we create them so just save this file like this and go back into your app folder into layout.dsx like that and inside the user provider go ahead and just add the model provider like this and you can import the model Provider from ad slash providers model provider like that so it's a self-closing tab it does not need to wrap any children inside of it uh great and if you save you can see how we have these text models right here don't worry we are actually actually going to change that to render a proper model great so let's go ahead and let's actually create that component but one thing I quickly want to fix before we go there so I want to go back into our types which we've written in the previous part and I want you to find the subscription interface like this and for the quantity I wrote string it needs to be a number like this so I just want you to have correct types I don't think the string would cause any problems but let's just have our types be correct great now I'm going to close everything here and I'm going to go into components and I'm going to create a new file model the DSX like this and I'm just quickly going to create this model component and for now it's going to return a div we're just going to say model component like that and then I'm going to go back into my providers into model provider and I'm going to render that model here so just go ahead and import that from add slash components model and as always I like to separate my imports so I know which ones are my custom Imports and which ones are packages like this great and you can see how now the text has changed to model component right here great so the package we're going to use to create our model is Radix so Radix is a type of headless UI so similar to headless UI so we only get The Primitives and we don't install the entire thing we only pick what we need from this in order to have it you can see the features it supports model and not model modes modes focus is automatically trapped can be controlled or uncontrolled basically a bunch of useful stuff for example the Escape key will close the model so that's great because we're gonna have proper interaction with our models so for that we need to run this installation right here npm installer addicts UI react dialog so let's go into our terminal here I'm going to shut down the application and I'm going to run npm install at Radix Dash UI dialog like that and I'm just going to expand this just a little bit so you can see it in the terminal like this go ahead and just press enter like that alright so I got an error here so let's see yes I made a mistake my apologies I didn't correctly read npim install at Radix Dash UI slash react Dash dialog like that my apologies all right and wait a couple of seconds for this to install now and after that you're going to be able to run your project again great so go ahead and run npn run Dev you can shut down sorry close uh the terminal and just refresh your component uh right here all right and now in this model component right here first things first I'm going to import that dialog which we just installed so import everything so use asterisks as dialog from at Radix UI react dialog like this great and we're also going to import an icon here so iomd close from react Dash icon slash i o like that perfect uh great and now we have to also Mark this sorry we don't have to do anything so model is just fine now let's write the interface so interface model crops is gonna have is open which is a type of Boolean like that it's going to have on change which is going to accept open which is a Boolean and a void make sure you don't miss Paul Boolean like that great then we cannot have a title which is a type of string we're going to have a description which is a type of string as well and children which is a react dot react you know like this perfect and now let's assign these props here so react.fc model crops like that and you can extract all of those so it's open on change title description and title uh and sorry children like this perfect and now we're actually going to go ahead and remove this div and use the dialog components here so I'm gonna go ahead and remove this and I'm going to write a dialogue that root like this great I'm Gonna Save this file you can see how now our model has disappeared uh sorry our text model component has disappeared from the top here and I want to go back into model provider and just for now I'm going to give you the title of test Model A I'm also going to give it a description of test description like this so I'm just going to collapse this attribute so you can see them in one line like that I'm gonna give it a hard coded is open I'm going to give it unchanged like this and it's gonna have some children so I'm just going to say test children like this and close the model like that and grade all of our errors now went away and we can now develop our model so make sure you do this we're going to remove this later but I want you to do this so you can actively see what we are actually developing so go back into your model.tsx here and let's go save and give some properties to this dialog.rootcomponent so open is going to be is open like that the fold open is going to also be it's open on open change it's going to be on change like this great now inside of that we're going to use dialogue dot portal like that uh and inside of that we're going to add a dialogue that overlay like this and that dialogue that overlay is actually going to be a self-closing component so you can move it like that and let's go ahead and give it some class names so I want to give it a class name of the following so it's going to have a BG Dash neutral Dash 900-90 so it's going to have an opacity uh like that and let's also give it a backdrop Dash blur Dash SM fixed and inset-0 like this and now when I added these classes you can see how our screen got darkened and blurred at the same time that's because we hard coded the is open here so if I remove this uh it actually won't appear but if I move it back there is open you can see how our model a background has opened great and now just below this dialog overlay we're going to add the dialogue content so go ahead and write dialog dot content here like this and one of what I want to do here is I want to give this some class names as well so go ahead and write class name we're gonna have fixed drop that Shadow Dash MD border border Dash neutral Dash 700 top Dash open uh square brackets fifty percent left dash 50 as well Max Dash H dash full on mobile so on mobile we're gonna take the full screen for our content H dash full as well uh medium so on medium devices we're gonna use uh the H dash Auto so it only fills how much it actually needs and an MD Max H is going to be uh 85 VH like that W full is the next class on mobile as well on MD we're going to use w-90 uh VW like this and envy is also going to have a Max W of 450 pixels like this great now let's also give it the Translate of minus sorry line translate Dash x dash minus 50 like this and translate Dash Y dash minus 50 as well so it's centered nicely you can see how I have this little line right here of course that is going to expand when we add some content there rounded Dash MD PG Dash neutral Dash 800 p dash open square brackets 25 pixels and you can see how it now expanded great and focus outline Dash none like this perfect so now our model content is starting to look like something perfect so now let's go ahead and inside this dialog content let's add a dialogue that title like this and inside we're going to render the title and you can see how it now says test model inside because in model provider we added that as our title great so I just want to give some class names uh to this dialog title right here let's go ahead and give it a class name of text XL text Dash Center font dashboard and mb-4 like this so now our title looks like that perfect and now just below dialogue that title we're gonna give it a description so go ahead and write dialog back description like this and inside all we're going to do is run the description for now so you can see how that looks the same the same way our title looked initially and now let's give some class names to the description so class name here go ahead and write mb-5 Pax Dash SM leading Dash normal and tax Dash Center like this great so now we have the title and the description centered like that perfect and now just below this description I want to open a div and inside I'm going to render the children so you can see how now it says test children in here so this is we're going to put our forms our buttons whatever we need basically uh great and now below this uh div right here I want to give it a dialogue that closed as child like this so it's going to have a prop as child and inside we're going to use the button element and it's going to render IO and the close icon like this great you can see how it put it right here but we're gonna position it right now so go ahead and write class name text Dash neutral Dash 400 hover text Dash white absolute top Dash open square brackets 10 pixels right open square brackets 10 pixels as well inline Dash Flex H is going to be 25 pixels inside of the square brackets same thing for width 25 pixels like this appearance is going to be a none items Dash Center justify Dash Center rounded Dash full and focus outline Dash nump like this great so we have a nice little icon right here and you can see how when I hover it closes uh it it it it changes the color to white great so that is it for our model component and we can now reuse it as many times as we want in our project great great job so now let's actually create our Alf model so for that I want to create a controller hook which we are going to use to trigger that out model and when we want to open it so let's go ahead and let's go into our hooks folder and create a new file use out model dot DS like this and inside we're going to have to install another package so I'm just going to go and expand this I'm gonna go into my terminal and I will write npm install to stand like this and just wait a couple of seconds for this install and npm run Dev again and just refresh your page if you haven't and you can see how on mobile view our our model takes the entire screen which is what we want button desktop view it only shows uh a nice little content in the sender great so inside of here I'm going to import create from two stand like this and then I'm going to create an interface Alf model store like this which is going to have is open which is a type of Boolean is going to have on open which is a avoid function on close which is a very same void function like this and then we can create const use out model is equal to create which is going to accept out model store inside of uh is pointy bracket so like here and then we're going to open parenthesis I'm going to open parenthesis again and I'm going to extract the set function from it I'm going to open an arrow function in here which is going to return an immediate object so first we open parenthesis again and then curly brackets inside of that and you just expand that great and then inside you can write is open to be false by default open sorry on open is going to be an arrow function which is calling the set which we extracted right here and open that and open an object and it's going to turn is open to True like this and you can just copy and paste on close on close like this and instead of is open to true it's going to turn is open to false like that great and just make sure you export default used alph model like this perfect and now what I want to do is I want to go uh into my components and I want to create a new component called out model the TSX like this great so just go ahead and write our model like this and make sure you mark this as use client like that and all I'm going to do inside is I'm gonna use our model component so we can import that from dot slash model like this and for now in the children all I'm going to render is out model children like this and I'm gonna go ahead and give this a title of welcome back like that and a description of login to your account like that I'm going to hard code is open and on change is just going to be an empty Arrow function like this great so you should not be seeing anything different on your desktop right now but we're gonna change that so I want to go back into model provider component here so inside providers going to model provider and completely remove this model and instead render out model like this it's a self-closing tag and then you can remove the import form model great and now we can see it should change to your alph model right here perfect so while we are in this Alpha model uh I want to install a couple of packages here so let's go ahead and let's install the following packages so I'm going to shut down my application right here I'm going to go ahead and install npm install at Super Bass dash out Dash UI Dash react like this so just wait a couple of seconds for this to install and then we're gonna have to install another package so npm install at Super Bass slash out Dash UI Dash shared like that great and then you can go ahead and npm run that your application again make sure to refresh if you haven't and I'm going to collapse this so uh it's all visible again great and what I'm gonna do now I'm gonna write uh uh uh I'm gonna modify these children to actually render the ALF model inside great so in order to do that first I need to get my Super Bass client so I'm going to write const Super Bass client is equal uh use super bass client from Super Bass out helpers react and I'm just going to start separating uh these Imports already and just execute this hook like this great I'm also giving the router so constant router is use router from next slash navigation like this great besides the router I'm also going to use the session so go ahead and write session is equal use session context like this which you can import from the very same Super Bass alt helpers react where you imported the use super bass client so I'm just going to collapse so you can see the import clearly like that perfect and now that we have all of that we are ready to actually render something different here so we're going to use the packages which we just installed so go ahead and render out which you can import from alph UI react like this so go ahead and import out from Super Bass out UI react like that and it's going to be a self-closing tag like this and we have to give it some properties so first of all let's give it Super Bass client like this and if you render you can see how this looks right now uh it doesn't look too good but don't worry we're going to give it some themes great so the theme I want to give it uh is a theme super so go ahead and write appearance like this open an object inside and write theme to be equal to theme super like this and you can import theme super from alt UI shared a package which we just installed great so you can see how this looks much better now but I want to modify just a tiny bit more so go ahead and write variables default inside of default you're gonna choose colors brand is going to be #or zero four zero four zero like that and Rand accent is going to be hashtag 22c55e like this great uh great so now we have uh these buttons and this um login screen right here and if uh we're also going to change the theme of it overall so right now it's in light mode so I just want to give it a theme dark like this great so that changes it and fits our view uh uh uh better nice and now what I want to do is I want to change what providers I'm using here so I'm just gonna directly modify providers to be an array and I'm just going to write GitHub inside great so now I only have sign in with GitHub so that's how you add the providers basically you can go to Super Bass and you can find any provider you like you can also try and see the autocomplete here so you can add Apple Azure bitbucket Discord Facebook basically a bunch of this uh even phone numbers great so I'm gonna only use GitHub for this tutorial like that um and one thing I also want to add see we also have the forgot your password functionality here we have the register screen so everything is here working immediately perfect uh and one thing I just want to add is the magic link so I'm just going to write magic link like this and then you can see that I have another option here so I can log in using the uh without my password I can just write in the email and it's going to send a link uh to my email great great job so now what I want to do is I actually want to use this I actually want to find a way to trigger this model so I don't want to keep it open by default so the way I'm going to do that is I'm going to use our use out model which we just created so go ahead and write const use out model you can import that from add slash hooks use alt model I'm just going to separate this like that great and inside I'm going to destruct on close and is open like this perfect so now let's go ahead and let's change the is open to is open like that and for the on close we're gonna write const on change here which is just going to be an empty Arrow function and it's also going to accept the prop open which is Boolean like this and if it's not open so if a question mark open make sure you don't accidentally write is open so we're going to use this parameter right here from the function so if it's not open then we're gonna trigger the on close like that and we're going to use that on change uh right here great so now we have to find a way to open that model since right now it is closed by default so let's go ahead and assign that so go ahead and find your header component inside your components right here and here where we have the login and the sign up we're going to open the very same model so in order to do that first we have to add our alph model options here so const use our model like this you can import it from ad hooks use at alph model like that and we're going to import on open like that perfect and now what I want to do I actually didn't have to do it like this you can also just write out model like that great so go ahead and use that and find these two buttons here so sign up button and login button and all you're gonna write is Alf model dot unopen like this just do not execute it accidentally like this so out model on open but do not execute it at the end great so now if I try and click login you can see how that nicely opens uh this little uh authentication model that we have that's exactly what we wanted perfect so now let's go ahead and let's go back into our auf model so go ahead and find the out model here and I'm just gonna write another use effect here that is going to close the model once we successfully log in or register so go ahead and write use effect you can import use effect from react so that's what I just did right here and I'm gonna move that to the top here great and inside of this use effect what I'm going to do is I'm going to check if the session exists so if there is an existing section a session in that case I'm going to Colorado that refresh like that and I'm gonna call on close like this and in the dependency array we're going to put session router and on close like this perfect so now when we are logged in so when we click sign in successfully we're gonna go and close the model great so now let's actually try this out so I suggest you have your super base opened in a new browser in a new tab so you can actually confirm that you have no projects sorry no users inside of here yet and no users should be in the users table right here I know I'm zoomed out but uh it's just because I cannot see clearly when it's too zoomed in all right so no users in your project yet and let's go ahead and let's try so I'm going to use my email here and I'm going to register I'm going to click sign in all right and we have invalid login credentials of course because I don't have this account so make sure you click don't have an account sign up and then click sign up and there you go here I have the message check your email for the confirmation link so now we have to confirm our mail and I'm just gonna quickly demonstrate that now so right here I got an email confirm your sign up follow this link to confirm your user and once I click here you can see that I am successfully signed in and you can see that I have this code in my URL right there great and you can see how my model automatically closed in my previous browser and if I try to uh uh I'm sorry yeah basically it it it um edit the session to my browser right now and if you go ahead and try and reload right here you can see that we have the user that register right here and it's great we can send them a password recovery a magic link we can play around with MFA factors or we can remove the user and also one more thing I want you to confirm is that I want you to so you should definitely have a user in your authentication tab but also go into the table editor and go into the users right here and you should have the user ID a new table row right here so great great job and now you can go ahead and try and log in with that as well so I'm gonna try and log in I'm gonna sign in and you can see how immediately it works uh great great job so you finished authentication and now I want to show you how to add GitHub because that's one thing we have not added here yet so I want you to go into GitHub go into your settings go all the way down to developer settings here and go ahead into all alt applications and create a new or alt app I'm gonna name it Spotify Dash clone and the homepage URL you can just copy the one you are here so localhost 3000 paste it here and the same for authorization callback URL so I'm going to zoom in so you can see and just click register application like that great and now you're gonna get the client ID and the client secret so go ahead and go into your project settings right here and we have to find our our providers right here so I'm just gonna pause a second to find that yes so go into your authentication right here and under configuration you can find the providers right here you can see email is enabled and I'm also going to enable GitHub right here so I'm gonna enable GitHub and of course we have to add the client ID and the client secret here so go ahead and add the client ID which you can copy from here and go ahead and generate a new client secret so I just have to confirm my identity and there we go I have my client secret now so I'm gonna copy that make sure you copy it because after you refresh you're gonna lose it and just paste in um the client secret great and you have the redirect URL here as well and just click save and that enables your GitHub login as well and you the same process for LinkedIn notion twitch basically whatever you want a great and now we're gonna go ahead and we're actually going to modify uh this header to act differently when we are logged in versus when we are logged out so let's go back into our header component here and let's just add a couple of stuff here so first we have the alph model and the router let's add the Super Bass client so const Super Bass client is equal to use super bass client you can import that from at Super Bass out helpers react like that and I'm just going to move it to the top right here great so now that you have that make sure you execute this hook so this is a working supervised client like that perfect and now I'm also going to extract the user from our use user hook but be careful how you're going to import this cell const like this is equal to use user and it's going to prompt you to import use user from Super Bass but we don't want to use that we want to use our own use user from add slash hooks use user so make sure you import your use user your use user from add slash hooks use user like that great and make sure you execute that as well and all we're going to extract for now is user like this right in the future we can also import extract subscription so you can see how cool this Hook is because that's how easy we're going to be able to check whether the user is subscribed or not great and now inside of this handle log out we can remove this comment for now and we can go ahead and write const error is equal a weight super based client that out that sign out like this great and since we're using a weight we also have to turn this into an asynchronous function like that great and after that I'm gonna call a router that refresh like this and I'm gonna add a comment to reset any playing songs in the future so we don't have that functionality yet but in the future uh I'm gonna write this as to do I want to reset if any current song is playing I want to shut it down because when your users are logged out they're not going to be able to play songs great and for now I'm just going to check if there is an error and I'm going to console log the error like this later on we're going to create a toast component for that but I doubt there's going to be any errors we're logging out uh great so now let's go ahead and let's use this handle log out but in order to do that we actually have to render the logout function great so for that we're going to use this user right here so let's go all the way to the bottom and let's find uh where our login and sign up buttons are great and now what I'm going to do is I'm actually going to uh go ahead and go Just A Step Above This fragment right here and I'm gonna open curly brackets and write user question mark and in here for now I'm gonna render just logged in like this and I'm going to create an alternative for this which is going to wrap this entire fragment like that great and you can now go ahead uh and indent that a little bit great so you can see how now it says logged in right here because we have the user perfect that's exactly what we wanted so let's go ahead and let's style this a bit better so I'm going to give this a class name of um blacks yeah x-4 and items Dash Center like that and inside of that I'm gonna render a button component so capital B with a text log out like this and I'm gonna add an attribute on click handle log out like this and class name is going to be VG Dash white px-6 mpy-2 like that perfect and just below that I'm gonna add another button component like this and it's gonna have an icon of a pay user alt like that and you can import fa user Alt from react Dash icons slash fa so I'm going to move that to the top as well great and now inside of here I'm gonna add a couple of attributes here as well so on click it's just gonna call router.push to slash account which does not exist yet so if you try you're gonna get a 404 error and class name is going to be BG Dash white like this great so this is how it's going to look when we are logged in and if I log out you can see how it switches back to this default login screen great so we completely finished our authentication and once I log in our screen changes great so before we wrap this up I just wanna add I just want to add I just want to fix this uh console log here so I actually want to use the toaster component for that so go back into your providers folder and create a new file called toaster provider .dsx like this go ahead and Mark it at use client like that and just import but we cannot import anything yet we have to install a package so let's go ahead I'm gonna shut this down I'm gonna expand this and I'm gonna write npm install react hot Dash toast like this wait a couple of seconds and then run your project again make sure you refresh your localhost if you shut down the application and let's import toaster from react Dash hot Dash toast like this and now let's write const toaster provider it's just an arrow function which is going to return the poster like this it's a self-closing tag and we're going to give it some toast options so I want to style it uh so open an object inside and write style background it's going to be hashtag 333 and color is going to be hashtag FFF like that and that's all we need for our stylus and just export default poster provider like this um perfect and and now what we have to do is we have to go in our app folder in our layout.dsx file right here and just above the Super Bass provider I want to add the toaster provider because toaster provider is independent of all of this Super Bass functions right here and you can import the toaster Provider from ad slash providers toaster provider like that and now we can go back into our header like here and instead of using this error I'm going to use coaster sorry toast which you can import from react hot toast like I did right here so the structure the toast and I'm gonna move it with the other Imports right here and I'm going to write those dot error error Dot message like this perfect and I just want to show you so else I'm going to write post.success logged out like this so save this file and if I click log out now you can see how I got this nice little message logged out which is exactly what I wanted perfect so that's it you finished authentication and you saw our use user hook in action and if everything is working for you so far that means you correctly set up all the super bass providers and the user providers and a quite complicated use user hook great great job so far so now we can actually go ahead and start developing our upload song model and we can finally start seeing some first songs here all right so now we're going to create a model that opens when we click on this plus button right here next to our your library text and that model is going to be used to upload songs to Super Bass storage and create a new record in the database but before I do that I want to protect this on the front end by triggering an authentication model if we are not logged in first so let's go ahead and let's find our library component so I'm going to collapse everything here and I'm gonna go into my components and I'm going to find a library right here and on the AI outline plus I already have an on click so I'm gonna find it here and we wrote a comment handle upload later so first let's add our out model so use Alpha model like that and you can import that from add slash hooks use out model like this great and now that we have that first thing we're going to check is whether we are logged in or not so in order to do that we also going to need our user so announced user from use user and make sure you import that from add slash hooks use user not the Super Bass use user we are using our custom hook right here great so execute that as well and then inside we're going to use if there is no user in that case return out model dot on open like that perfect so go ahead and save that and since I'm not logged in when I click on the plus sign it's going to open this and now if I try and log in like this and if I try and click again nothing happens great that's exactly what we want so now let's go ahead and let's create a controller that's going to control our upload model so for that to make it easier you can go into the hooks folder right here and what you can do is you can just copy and paste the existing use alph model so go ahead and copy and paste that and rename that to use upload model.ts like that great and now inside I'm going to replace all instances of alph model like this to upload model so you should have the upload store the use upload model and use upload model as well perfect so we have that ready now and now you can go back in your library components go ahead and find the library right here and add that hook here as well so const upload model is equal to use upload model like that and then you're gonna check and just return upload model dot on open like this and we can remove this comment here and I'm going to add a different comment here to do um check for subscription so later when we integrate stripe we're gonna do the very same check but instead of checking for user we're going to destructure subscription from here and we're going to check whether we have the subscription or not and if we don't we're going to trigger the subscription model which is going to exist later on perfect so now if you click nothing's gonna happen because we don't have the upload model so let's go ahead and let's create that component I'm gonna collapse everything I'm gonna go into components right here and I'll create a new file upload model the TSX like this perfect so let's go ahead and write upload model like that and all it's going to do for now is uh use the dot slash model like this we're going to write upload content inside like that I'm gonna go ahead and give you the title um of upload model title and a description of upload model description like this I'm gonna give it an is open and on change is just going to be an empty array like this perfect so now we have the upload model and what we have to do before we can trigger it and actually assign uh make this not hard coded so yeah of course we're going to change this in the future we have to add it to list of our model providers so let's go ahead and let's find our providers right here and go to model provider and where you added the elf model just below that add the upload model as well and you can upload import the upload model from add slash components upload model like that and if you save you're gonna get the upload model right here because we hard coded it to be opened always so let's go back to upload model and let's use the use upload model hook so const upload model is equal to use upload model like that and you can import that from add slash hooks use upload model and if you save just remember to also could use client at the top like this so it doesn't trigger any errors great and now we're going to change this is open to be upload model that open sorry that is open like that and we're going to create a custom on change here so go ahead and write const on Change is Going to Be an Arrow function and it's going to accept a prop open which is a Boolean like this and if it's not open in that case uh we're going to uh I'm just going to write a comment reset the form when we add the form later on and upload model that unclose like this perfect and then just use this on change and replace that with this Arrow function perfect and now if you click on this you can see how our upload model closes uh great great job it's exactly as we wanted if you log out you can see that it triggers the authentication model so great on the front end our upload is protected so just make sure you're logged in and open your upload model right here and let's go ahead and let's actually um add some functions here so first I wanna change this title to add a song like this and I want to give this a description of upload and MP3 file like this great and what I'm gonna do inside of there is a gonna be our form like this but before we start developing our form um we're gonna have to uh add our a package called react hook form so let's go ahead and let's do that so open your terminal and inside of the terminal I'm just going to expand my screen like this I'm going to shut down the app and I'm going to write npm install react Dash hook Dash form uh sorry react hook Dash form like this so emptin is all react Dash hook Dash form like that perfect and we're also going to install another package npm install unique ID like this and I'm pretty sure we're also going to need the types for that so just go ahead and write npm install Dash capital d add types slash unique ID like this great so previously uh we installed a unique ID and I'm just gonna check in my package Json if everything is all right so I should have the new react hook form here I do I have the unique ID and I also have the types for Unique ID perfect uh great and now we can go ahead and actually start creating our a used form here so let's go ahead and let's create const like this and let's write use a form like that and you can import that from react to form and I'm going to put that at the top right here uh great and the values inside are going to be field values like that and you can also import that from react hook form and go ahead and open parenthesis open an object inside and let's give this some default values so it's going to have an author which is an empty string it's going to have a title which is an empty string it's going to have a song which is null an image which is null as well so the reason I'm putting null here because they're not going to be strings they're going to be files perfect and from this we're gonna extract the register and we'll submit and reset like that great and now we can safely call the reset here in this comment so reset like that so every time we close the model our form is going to be safely reset perfect so that's exactly what we want and now let's actually go ahead and let's write the on submit function so const on submit like this um upload to Super Bass comment like that and let's go ahead and let's write a small form here so I'm going to write a form like this and I'm gonna give this a function on submit which is going to call handle subnet now it's going to get the handle submit from this use form and then we're gonna wrap our own submit inside of that and then we can give our own submit some special types so go ahead and give it a type of submit Handler which you can import from react hook form right here where we use the use form and field values like that and also open pointy brackets and give it field values which we already have imported great and now you have access to values and these values are going to be the author title song and image which are going to be controlled from our inputs inside the form great and just remember to put async because this is going to be uh we're going to use some awaits inside of this method right here perfect so we prepared that function and now we can go ahead and we can prepare our first input which we're gonna have to create so let's go ahead and write input like this so it does not exist yet so if you save of course you're gonna get an error because input does not exist so let's go ahead and let's write ID title like this uh make sure the uh yeah make sure to run your project I forgot to run it so npm run Dev so that's why I didn't get the error all right and let's give this a disabled up is loading now currently we don't have the is loading so let's quickly go uh and resolve that so I'm gonna use this is loading and I'm going to create a state right here so const is loading set is loading is equal to use state which you can import uh from react right here and I'm gonna move it to the top like that perfect we still have the error because input is not defined but before we Define it I just want to give it a couple of more props which we're going to need while developing the input go ahead and spread the register function inside where do we get the register well we destructured it from use form and open parenthesis inside of here and go ahead and make sure that you for the name you have to put in the same as ID so in our case title like this great and also make sure you add a object for the second parameter and write required true like this so what this register is going to do is going to spread uh a bunch of uh uh props and attributes that we need for this input such as uh on on change on blur on Focus uh it's gonna pass the name it's going to pass a bunch of useful props to us great and let's give this a a placeholder of song title like this perfect now let's finally go and resolve this this Arrow right here so I'm gonna go into my components I'm going to create a new file input.dsx like that and inside I'm just quickly going to go ahead and fix the error so input like this and I'm just going to write a div input like that go back to your upload model and just import input from dot slash input like this so it's in the same folder so that's why we can use it like that perfect and make sure you open your model so you can see what you're developing great now of course we have some types error here so let's go ahead and let's resolve that so first I'm going to write an interface for this and we're going to use a similar structure to what we did with our button components so we're going to use forward ref so we can safely reuse all of the attributes which are available in the native input element so go ahead and write interface input props like that extends react dot input HTML attributes open pointy brackets h HTML input element like that and just pass in the empty object at the end perfect and now what I'm going to do I'm going to remove this and I'm going to write is equal forward ref like this and you can import forward ref from react go ahead and for the first uh element for the first attribute give it HTML input element and for the second input props like that go ahead and open parenthesis inside and open parenthesis one more time and then you can open an object inside like this great and before we write something inside let's go ahead and write input dot display name is equal to input like this perfect and now we can safely destructure some elements here so class name type whoops type like this disabled and the rest is going to be called props like that and after the curly brace or or the end of the object you're going to pass in the ref as well and then just open an arrow function like this and then you can return some jsx in our case that's going to be the native HTML input element like this great and make sure you keep this opened so great you can see how we have a nice little input here so now let's go ahead let's give it some classes let's assign some attributes to here and whatnot so first let's give it a type type like that and now let's use class name TW merge you can import TW merge from Tailwind merge like this again I'm going to use backticks because I want to collapse this in multiple classes you can use normal strings if you want you don't have to use backticks and let's give it a flex W Dash full rounded Dash MD BG Dash neutral Dash 700 border border Dash transparent like that px-3 py-3 text Dash SM file border Dash zero so file is going to be a special styling if we assign the type of the input to be file and since we're gonna upload files we're gonna need that file is also going to have a BG transparent like that file is going to have a small text file is going to have a font medium like that placeholder is going to have a tax Dash neutral Dash 400 like this uh on disabled we're gonna have a cursor Dash not Dash allowed like that and disabled it was also going to have an opacity of 50 and on the focus we're going to use outline Dash num so we don't have that uh bad looking outline great uh and let's go ahead and add a comma after this and all I'm going to pass in here is class name like that so I can always modify my input if I want to do so great and besides the class name we're also going to pass in disabled disabled ref ref and we're gonna spread the rest of the props inside and now you can see how I have a nice song title in here so that's it for our input component great and now we go back into upload model and we can start adding some other fields so uh along with title you can go ahead and copy and paste this and this one is going to be author like this so go ahead and also put the author in this register so always make sure that your ID and your register is the same same here like this title and title and for the placeholder we're gonna add a song author like that so great now we have two inputs here and let's just give a class name to this form element so our inputs are a bit more uh separated so I'm going to give it the class name of flex Flex Dash coal and GAP Dash Y dash four like this great so now our input separation looks better perfect uh and now what I'm gonna do is I'm gonna create a div like this and inside I'm going to create another div and I'm going to write select a song file like this and I'm going to give this a class name of pd-1 like that so select a class name and then you can go ahead and copy the input one more time and below this div right here you can save and we're going to change the ID um to file like that the register is also going to be uh sorry you can change the ID to song my apologies ID is a song type is a file like that so IDE song that means in register we also have to change the song like that the placeholder does not exist on the type element uh as far as I know my something might have changed and we're gonna add the accept so we can only accept dot MP3 files like this perfect so now we have that ready and you can see when I click choose file uh it's going to open a folder and you can see how it only I can only select songs from my file I cannot select images I can only use um the MP3 files perfect that's exactly what I wanted and now what we're gonna do we're going to copy this entire element right here so along with this div right here and paste it and now you should have two instances of this but the second one is going to be select an image like that and this is going to accept image slash asterisks like that ID is going to be image and in register also change it to image like that great so now if I click choose file you can see how I can only select uh jpeg images I cannot select uh MP3 files perfect so that's exactly what we want great and just uh below this last div go ahead and add a button element and you can import that from dot slash button so we're going to use our custom uh button element you can see how I import it here great and it's just gonna write create like that and we're going to give it a disabled of this uh is loading and type is going to be submit great so when we click on this it's going to call our uh submit function which we added to our form but since we have put required on all of this it's not doing anything because it's not allowing us to submit perfect so now that that is ready we can actually go ahead and open a try and catch block here so I'm gonna write try and I'm gonna Also let's see if we're gonna catch the error in some way yes we are so catch error like that and first let's write post which you can import from react hot toast like that I'm gonna move that to the top great go back here toes dot error and we're just going to write um error sorry actually we're going to write something went wrong like that perfect uh great and now in this try let's go ahead and write set is loading the true like that and let's just modify this in the is loading and set is loading give it default value of false so it knows that it's a Boolean in the beginning great and now we can go back to on submit and the error should go away here great and let's also add a finally set is loading false like that perfect and now we can focus more on this uh try block right here so first let's extract our image and song file so const image file is going to be values dot image question mark DOT first element cons uh song file is going to be values Dot Song question mark DOT first file as well like that great and now we're gonna check if we have all the missing Fields if we have all the fields needed so if there is no image file or if there is no song file or if there is no user so we're also going to check for user one more time here so go ahead and write const user from use user Make sure you import that from ad hooks slash user like this so add hooks slash user like that so don't use the supervised one so if we don't have that in that case I'm gonna call those that error missing Fields like that perfect and I'm going to return the entire thing so I don't go anywhere further great so the return is important otherwise even if we don't have this we're just gonna toast an error and then we're gonna continue and try and upload and it's not gonna work so it's better to prevent it like this with a return uh great and now let's define a unique ID which we're going to use to safely store and name things in our Super Bass bucket uh so go ahead and write const unique ID is equal unique ID like that and let's go ahead and let's import that so I'm going to just right here at the top import unique ID from unique ID like that make sure you have the types installed for that so I'm gonna confirm one more time how this is supposed to look so unique ID you need to have unique ID in your dependencies and add types unique ID in your Dev dependencies like that go great let's go back to upload model here and now that we have this unique ID we can use that to safely um to safely upload our songs so before we do that we're going to need our Super Bass client so let's go here to the top where we Define our use user and let's write const Super Bass client is equal to use super based client like that and you can import that from at Super Bass out helpers react perfect and now we can actually go ahead and write the code to upload Our Song and image perfect so let's go here where we've written our unique ID and I'm going to write a comment upload song so first we're going to upload Our Song so go ahead and write const is equal await super based client like that and from the super based client uh I'm gonna extract data and I'm gonna remap it to song data and I'm going to write error and I'm going to remap it to song error like that because we're going to have multiple data and errors so we have to remap them so they're functional great and now in the super based client go ahead you can write this all in one line dot storage like this prom choose a bucket in our case I'm going to choose songs so how do I know what bucket to choose from well you can go back into your Super Bass right here so I'm gonna go to the home page and go ahead and click on storage in the sidebar and you can see we created two buckets songs and images so first go ahead and select the songs because that's what we are going to upload first all right so in the songs go ahead right from songs dot upload and now we're going to create a unique name for our file so what I'm going to use is a song Dash make sure you open backticks because we're going to use some special templating inside so song Dash values dot title like that Dash unique whoops ID so this constant which we've written right here and on the second argument I'm gonna pass in song file and on the third argument I'm gonna put in Cache control I'm gonna give it a string of 3600 and absurd or false like that perfect so now this is going to successfully upload the song Perfect now let's go ahead and check if there was any errors were up while uploading Our Song so if song error in that case we're going to set set is loading to false because we're gonna break the entire function and just write return those dot error failed song upload like that great now let's go ahead if everything went correctly now I'm going to write a comment upload image like this so you can go ahead and just copy this entire thing for upload song and just paste it here great so you're gonna have two things now but instead of song data this is going to be image data and instead of song error this is going to be image error like that and the rest can stay the same except we're going to change the from to use images why images well in our buckets we have the images bucket so that's the one I want to use and instead of the name uh song here I'm going to use image and instead of passing the song file this is very important don't forget to actually change it to the image file like this so you both of your values need to be used the image file and the song file in the first upload we use the song file where we have the song the title the songs buckets and in the second one where we have the image and images we use the image file and the cache control and upsert can stay the same perfect and now we're going to check if we have an image error so if there is an image error in that case set is loading to false and return toast dot error failed image upload like that perfect otherwise if everything went correctly if there was no image errors or song errors we can go ahead and actually create a record in our database uh you can go here and see we have the songs so this is where it should appear and if you take a look we have some Fields like title and song path and image path and that's what we are going to use so this is going to be our path this uh generated title so image Dash the title and unique ID so that's how we are going to be able to fetch them from Storage later on great so now let's go ahead and let's write it the following function so const weight Super Bass client and I'm gonna extract an error here so the error is going to be error but I'm going to remap it to Super Bass error like that perfect so I'll wait Super Bass client and go ahead you can write this in one line if you want from so we are writing uh an SQL insert query now so we have to choose what table to insert to so go ahead and write songs because that's the table we want dot insert like that and go ahead and open an object and I'm going to pass in the user underscore ID with user.id I'm going to pass in the title from values.title like that the author is going to be values.author like that image underscore path is going to be image data dot path like this and song underscore path is going to be songdata dot path like that perfect and if that went correctly so first let's check the error so if there is a Super Bass error in that case return post error superbase error Dot message like that and set is loading the false like that perfect otherwise if everything went correctly we're going to call router but we don't have the router yet so let's go ahead and let's just go to the top of our file and add a router so const router is equal use router from not next slash router my mistake from next slash navigation so make sure your use router is from next slash navigation and I'm just going to move these two to the top with the other Imports and make sure you execute this hook right here so you can use your router and you're gonna write router.refresh that's going to be useful when we actually list out our songs set is loading the false like this and tells that success song created like that perfect and then we're going to reset the entire form and we're gonna close uh the upload model like that perfect so that is it for our upload model here and now we can go ahead and try and do this so go ahead and find an MP3 file and find an image if you want to you can find them in my GitHub repository so you can go ahead in my repository in the description and find the song files folder and I'm gonna leave an MP3 file and an image for you here or you can find anything you want online great so let's go ahead uh and let's try this so I'm gonna give this a title of all of me like that and I'm gonna give this uh an author of Antonio for example let's select a song file so I'm gonna select all of me.mp3 like that and let's select an image so all of me image like this and let's click create and let's see if we get an error perhaps or if the upload model is going to close so just be patient because it's uploading right now to the bucket uh we have to see there we go so we have a song created and the success message right now we don't see anything here but let's go and let's check here so there we go you can see in my database I'm going to expand this so we can see better in the database great so I'm gonna zoom in you can see that I have a first song here you can see when it was created you can see the title all of me you can see the song path that I have and you can see the image path that they have the author and the person who created that but what's more important for us is that the files have been uploaded in the storage so let's go into songs here and you can see that I have a song All of Me with a unique ID and the same thing for the image and that those very IDs are mapped correctly in my song record so in the future I will be able to safely uh refer to them and download them and play them or show them whatever I want to do with them great so if you want to you can go ahead and add a couple of more songs so that's what I'm going to do I'm gonna go ahead and add this song for example uh deep Stone by let's say Mark I'm gonna select an image like this so I just want to have a couple of these songs I advise you do the same add a couple of songs if everything is working correctly for you uh just always be patient when this is uploading since they are uh larger files a bit and I'm just gonna check again there we go so it worked for the second time you can see that I have the song path the image path uh the author everything perfect and I'm just gonna confirm my storage yes I have the image and you can see uh it loaded the image correctly as well great that's exactly what we want and if you want you can also test uh your song right here if it was uploaded correctly perfect that's exactly what we want and now we are ready to start loading our songs great great job so now let's go ahead and let's find a way to list our songs which we just uploaded here so I'm going to go back into my code right here I'm gonna collapse everything and I'm gonna go into the app folder into the site in page.tsx right here and the first thing I'm going to do is I'm going to write export const revalidate 0 like this so this means this page will not be cached and the data on it will always be up to date great and what we have to do now is we have to create an action that is going to load our songs in our server component so for that what I'm gonna do first I'm just gonna extend my code view a little bit so I can expand the sidebar and I'm going to create a new folder in the root of our application called actions and I'm going to create an action called get songs.ps let's go ahead and write get songs it's an asynchronous function like this and it returns a promise an array of songs like this and open an arrow function so obviously we need to create the song type before we move on so for that we have to go back into our types right here and let's go ahead and let's build the song so I'm gonna write export interface song ID string user underscore ID string author string title string song underscore path string and image underscore path string as well great and now we're going to go back in get songs and I'm going to import this from at slash types like this perfect and now that that is done we can go ahead let's just see all right that is fine now we have to create uh the server component uh Super Bass client so let's go ahead and do that so let's go ahead and let's write const Super Bass is equal create server client like this so create server component client exactly like that perfect and inside of that we're gonna pass in the headers and cookies and we have to import both of those from next slash headers so go ahead and write import headers and cookies from next slash headers like this perfect and now I'm just going to go ahead and resolve this error quickly so my apologies uh we do not need headers at all so if you use create server component client from superbase out helpers you don't need the headers now if you getting an error here or if you cannot find the import create server component client make sure that the packet Json you're using so go in your packet Json and make sure that your out helpers react are on the same version that mine are same for the next JS because a lot of stuff has been deprecated with the new version and introduction of next 13. great so now that we have that then we can safely go ahead and fetch our songs so cons data error is equal await Super Bass like this Dot from we're gonna choose songs select select a star so everything inside and Order we're going to use created underscore add ascending balls like this perfect and then if there is an error we're going to console log the error like that and then we're going to return data as any or an empty array like that and Export default get songs like this perfect so now that we have that and we don't need the headers uh sorry we don't need the cookies uh yeah but we don't need the headers we need only the cookies for the create server component client like this perfect and now we can go ahead and we can go back into our page so go ahead and find the page that DSX right here and I'm gonna write con songs is equal await get songs like this perfect and in order to use a weight we also need to make this an asynchronous function like that and make sure your import gets songs from add actions get songs like this great and now that we have our songs we can actually go ahead and try it here so I'm gonna go songs .map song and I'm just gonna return a div song dot title uh like this and an empty div and I just want to quickly save this this and there we go I have deep Stone and all of me so the two songs that I uploaded perfect that's exactly um what we want and now instead of this div right here I'm actually gonna make page content like this so we didn't have page content right now so go into your site folder create a new folder components and inside create a new file page content the TSX like this let's go ahead and quickly fix the page content here like that go and make sure you mark this as use client like that and then go back into your site page.vsx and just import this page content from dot slash components page content so not in the global components but this is only the component for that uh for that for this site right here I'm passing the songs like this great and now we can safely go into the page content and we can develop a stuff here so first I'm going to go ahead and write the interface page content props like this which accepts songs go ahead and import this type and put it as an array right here and then assign this prop so react.fc page content props like that and go ahead and get the songs like this perfect and now what I want to do is first I want to check if there are no songs so if songs length is equal to zero in that case I'm going to return a div which is going to say no songs available like this and a class name mt-4 tax Dash neutral Dash 400 so I'm just going to quickly change this like this so you can see how that's going to look see how we have the text no songs available just remember to put it to equal zero uh in the future great uh and what I'm going to do now is I'm going to create a grid to show our song so instead of rendering page content I'm going to remove that and I'm gonna give this a class name of grid grid Dash calls Dash 2 SM grid Dash close Dash three MD grid Dash calls Dash three again LG grid Dash calls Dash 4 XL grid Dash calls Dash five like that and to excel grid Dash calls Dash 8 like that yeah Dash 4 and empty-4 perfect and now inside of this div we're going to iterate over our songs so songs.map item and we're gonna immediately return song item like this and we're gonna pass in the key which is going to be item dot ID and we're gonna pass in on clicked which for now is going to be an empty Arrow function and key we already passed the key so we're going to pass in data as item like this and if you save you're going to get an error because uh song item does not exist so let's go ahead in our components file folder and create a new file song item the TSX like this let's quickly fix the error so song item like that I'm going to return a div song item and I'm gonna mark this uh as use clients so I don't forget about it and I'm gonna go back into page content and I'm going to import song Clan from add slash components a song item like this and the error should go away and you can see how I have two song items here and yes we have a typescript error we're gonna resolve that now so let's go ahead and that's actually write an interface song item props data song and you can import this from ad slash types and on click ID string void like that perfect and make sure you don't do a typo here and now let's assign this prop so react.fc song item props and go ahead and extract the data and on click like that perfect and now I want to create a hook that's going to help us to load an image for our song so let's go ahead and let's create this hook called use load image so go into your hooks folder use load image dot DS and first I want you to import the super based client so const use load image it's going to accept a song which is a type of song which you can import from types and let's write con Super Bass client is equal to use superbase a client like this and I just want to move this a bit older like that perfect so now that we have this uh first let's check if we have a song so if we don't have a song just return null like this otherwise go ahead and use data remap it to image data like that from superbase client dot storage from choose a bucket in our case it's going to be images and get public URL song.image underscore path like this perfect and then just return image data.public URL like this and Export default use load image like that perfect and now we can go back into our song item and we can continue developing so first let's get the image pad so const image path is equal use load image which you can import from add slash hooks use load image and pass in the data like that perfect and now in this return let's go ahead and give it some classes and some attributes so on click it's going to be an arrow function which calls on click data.id like that and class names are going to be the following so we're going to have relative group blacks Flex Dash call items Dash Center justify Dash Center rounded Dash MD overflow Dash hidden Gap x 4 BG Dash neutral Dash 400 slash Five four hundred five like that cursor Dash pointer hover BG Dash neutral Dash 400 slash 10 like this and transition np-3 like that great so you can see how we have two little boxes here and only hover them it's a nice little effect perfect and now inside I'm gonna add the image so go ahead and remove this text song item and just write a div like this and that's gonna go ahead and give this div a class name of relative aspect Dash Square W Dash full H dash full rounded Dash MD and overflow Dash hidden like that perfect and inside of that we're going to use the next the JS image so go ahead and import image from next slash image I'm going to put that at the top right here great it is a self-closing tag let's go ahead and give this a class name of object dash cover like that a source is going to be image path like that or for now what I want to put it I'm just going to reuse my public images like that PNG so slash Images slash lite.png so I'm going to reuse that and I want to give it uh a fill and ALT image like this perfect uh all right let's Okay so what we have here is an error from Super Bass because uh this specific URL is not configured in our next.config.js I'm just gonna zoom in on this so you can see so you're going to get the exact same error or this one you cannot use images that don't have configured uh their URL in next.js config so in order to fix this we have to add that to nextconfig.js but for you it's gonna probably be a different link so this specific ID is my Super Bass reference ID if I go in my project settings you can see that is my reference ID so for you it's going to say something different but similar to that so make sure you copy whatever it is inside of this parenthesis so this is going to be different for you but copy the entire URL like that and go ahead and go into your next dot config.js right here uh open this object write images domains open an array and just paste in that specific URL and then you can refresh your page and I'm gonna go back uh into song item component right now all right I'm going to zoom out and there we go you can see how I have two images of my songs here perfect so that's exactly what we wanted nice and now below this uh div which renders the image let's go ahead and write the title so I'm gonna give this a div a class name of flex Flex Dash call items Dash start W Dash full p dash four and GAP Dash Y dash one so make sure you add all of these classes to that perfect so it creates a nice little space for us then inside of that create a paragraph with data.title like this and I just want to give this a class name of fond Dash semi Bold frontcate And W Dash full like this perfect and now what I want to do I want to go below that paragraph and open another paragraph and inside I'm going to write buy data dot author like this so it says it like that perfect and I just want to give this a different class name so it's going to be text neutral Dash 400 tax Dash SM pb-4 W Dash cool and I'm also going to give you the class of truncate all right if you keep getting this uh loading chunk error uh just remember you can always shut down your application so that happens when you change your next config in the middle of development so I'm just going to completely restart uh the project and the error should stop being in an infinite Loop now great so just wait a couple of seconds for this to reinstall now and there we go we have it here uh great so we added that now and what I want to do now is I want to give this a another div right here so create another div here and inside we're going to render our play button I'm just going to write it like that and give it a class name of the following so it's going to have absolute bottom Dash 24 and write Dash 5 like that so this is where we're going to position it and it's of course gonna be a much better looking and I just want to quickly fix a mistake I made so uh we'll find the data.title here and this other div so it's not p dash four it's pt-4 so it's like this great uh and now let's go ahead and let's uh write this play button here like that I'm Gonna Save this uh and of course nothing's gonna happen now I mean we're gonna get an error because play button does not exist so let's go ahead and let's create that so inside of your components create a new file play button.tsx I'm gonna quickly create it so sfc play button like that div play button like that and now let's go back uh in our song item component and let's just import it like this throw dot slash play button perfect and now that we have that we can go ahead and actually style this play button so instead of a div it's going to be a button like this and the icon is going to be fa play which you can import from react Dash icon slash F A like this and I want to give it a class name of textlash black like that perfect and now let's go ahead and let's give some styles to this button so class name here is going to be transition opacity Dash zero rounded Dash pull blacks items Dash Center VG Dash green Dash 500. p dash four drop Dash Shadow Dash MD Translate Dash Y dash one fourth like that group Dash hover opacity 100 group Dash hover translate Dash Y dash zero and hover scale 110 and now you can see when I hover on these elements we have a beautiful effect of the play button great so that's exactly what I wanted to do and now if you keep adding more songs you're gonna see how they uh they are added here in real time so you can go ahead and try that great and now we have to create a couple of more way to load our songs so in this library right here in this list of songs I only want to load songs that we ourselves have uploaded so not all songs like we did with our page right here where we used get songs so we're going to create a special action to get our own songs which we uploaded in our case that's going to be exactly the same but if you have multiple account pounds you're gonna see the difference so let's go ahead and do that now but before we move on if you have any problems loading your songs that's that could be because we have not created a middleware so obviously it works for me but if you have any errors uh let's go ahead and let's quickly create that so what you want to do in the root of your folder you want to create a new file called middleware whoops my apologies I was focused on the other window middleware dot DS like that and what you're going to create inside is the following so go ahead and write import create middleware client from superbase out helpers next JS and import next response from next server like that great and now inside of that write export asynchronous function middleware request and write constress is equal to nextresponse dot next like that on Super Bass is equal to create middleware client and it's going to accept a request and response so we obviously have to add that as well so go ahead and write uh Rec and address like this great and what you want to do next is just write um a weight Super Bass dot elf that gets session like this and return press like that perfect and if you also have to assign a type to this request which is a type of next request which you can also import from next server great so now you have this middleware so the reason it's working for us is because we did not add any restrictions for authenticated users to be able to load songs but this way even if you change that it's going to work with authenticated users great so now we can go back and we can go into our library component and actually load these songs so let's create an action get songs by user ID grade so I'm just going to expand this a little bit more and I'm going to go into my actions and you can copy and paste this get songs and rename it into get songs by user ID like this great and rename that here as well so get songs by user ID here perfect everything stays the same and you can go ahead and remove this for now because it's going to be a little bit different so first we have to get our session so cons data session data error session error and I'm just going to collapse this too so first we have to get that session all right as that's going to be equal to a weight Super Bass dot out that get session like that perfect and now we're going to check if there was an error so if there was a session error in that case we're going to console log session error Dot message and we're going to return an empty array great and now let's go ahead and write const data error like that from await Super Bass Dot from songs go ahead and write dot select put in asterisk dot equal user underscore ID session data dot session question mark dot user dot ID like that and that order created underscore add sending balls like this perfect and if there was an error on the log error.message like that perfect and then just the return data as any or an empty array perfect so now we have our function to get songs from the user who created them and we're going to put this function in our layout so let's go ahead and let's go into the app folder into layout dot DSX right here and first things first let's turn this into an asynchronous function like that and then in here I'm going to write const user songs is equal to await get songs by user ID like that and you can import that from add slash actions get songs by user ID and let's also write export cons revalidate zero because we don't want this layout to be cached either and now that we have these user songs we can pass them to our sidebar which is going to provide them to our library so I'm gonna pass these songs to sidebar like this and now we have to go inside of that sidebar and we have to change the props a little bit so besides children it's also going to accept songs which is a type of song which you can import from the types like that and make sure it's an array like this great and now we can extract songs here and now we can safely uh add the songs to our library components so go all the way down and just pass them here one more time songs like that so yeah we do a little bit of prop drilling but it's only on two levels and we are using a server component so I think it's completely fine so let's go back uh into our library component and of course we have to create an interface here so interface Library props songs is a type of song which is an array great like this and now just assign that so react dot FC and extract the songs exactly like that and now what you can do is you can map over those songs right here where we write the list of songs so I'm gonna go ahead and write songs about map item and I'm gonna return a div item dot title like this just to see if it works and it does work so in my library here I've loaded deep Stone and all of me two of the songs that I've uploaded and now I'm gonna replace this with media item like that it's gonna have an on clicked uh actually for now let's just make it an empty Arrow function because we don't have the player functionality yet the key is going to be item.id and data is going to be item like that obviously uh if you save you're going to get an error but don't worry we're going to fix that so go into components go into media item dot PSX like that let's just return a div media item and let's mark this as use client as well let's go back into the library and just import that at the top right here great and there we go now we have two instances of midi item right here and now let's actually assign some props to it here so interface media item props like that data is going to be song which you can import from Types on click it's going to be an optional ID string void like that and then you can use this media item props and assign those right here great now inside just extract the data and on click great and let's get the image URL first so const image URL is equal to use load image which can import from add slash hooks use load image and pass in the data like that perfect now let's write our on click so const handle click like that if there is an on click in that case we're going to return on click data.id and otherwise well actually that's going to be is I'm going to write a comment uh default turn on player but that's going to be for to do because we don't have a player yet great and now that we have that we can go ahead and start styling our media item here so I'm going to remove this and I'm gonna start giving this an attribute of on click handle click like that class name is going to be Flex items Dash Center Gap Dash x-3 cursor Dash pointer hover VG Dash neutral Dash 800 -50 W Dash full E-2 and around it Dash MD like that great and now inside of that I'm gonna go ahead and open another div it's going to be an image div so I'm going to give this a class name of relative rounded Dash MD minimum Dash height Dash square brackets 48 pixels we're gonna do the same thing for width like this and overflow Dash hidden like that perfect and inside uh we're gonna add an image element from next slash image like that so make sure you've imported image from next slash image I'm just going to move that all the way to the top like that great and now that you have that give it a property of fill and source is going to be image URL or it's going to be slash images like that PNG like that let me just confirm that it is dot PNG so basically this file right here yes it's liked.png and ALT is going to be media item and class name is going to be object dash cover like that and great you can see how now I have two elements right here and you can see uh clearly see the image great and now outside of this div which holds uh the image I'm going to go ahead and write another div the class name of flex Flex Dash call Gap Dash Y dash one overflow hidden inside open the paragraph and render data.title and give that a class name of text Dash white and truncate like that and below that open another paragraph and render data dot author like that and give this a class name of text Dash neutral Dash 400 tax Dash SM and truncape like that great you can see how great this looks we're going to reuse this media item component many times in our project great so that's it that's how we loaded our library right here so I'm going to try and upload another song so you can see how it gets updated now so I'm gonna try and write test by John for example I'm going to choose a song for example and I'm going to choose an image here I'm gonna click create I'm gonna wait a couple of seconds uh and we're gonna see uh what happens now so let's just give it some time to upload and when it uploads there we go you can see how nicely it refreshed my library and the newest songs right here great uh what we have to do now is we have to create a way to load uh uh search songs so we're gonna create the search page and a way to search through our songs so let's go ahead and let's create an action that is capable of fetching songs depending on the title so I'm going to go ahead and expand my code here I'm going to close everything I'm going to go into actions and I'm going to copy this get songs right one more time and I'm going to rename this to get songs by title like that great and I'm going to rename the action inside get songs by title as well and this one is going to accept a prop of title which is a type of string like this great so this study is the same and first let's check if there is no title so if there is no title we're gonna get all songs so const all songs is equal to await get songs which you can import from dot slash get songs like that and just make sure to execute it and return all songs perfect otherwise we're gonna go ahead and modify this a little bit so we're going to select everything but we're gonna add uh one more option here Dot I like like this so make sure there is an i before like and inside we're going to choose the Field title and we're going to compare it to open template literals and go ahead and put this percentage signs and inside of this percentage signs go ahead and open a template and write the title so this is going to give you a precise search algorithm great and we're going to order them in the same way and that's it so that's all we need for our get songs by title uh what I want to do now is I want to create our search page so I'm going to close everything here I'm going to go into the app folder and I'm going to create a new folder search like that and inside I'm going to create a new file page.dsx like this great so let's go ahead and let's write an interface first so interface search props we're gonna have search params which is going to have a title which is a type of string like that great and now I'm going to write con search is equal to async foreign like this go ahead and use search params which is going to be a type of search props like that and just open and return a narrow function and first let's fetch our songs so const songs is equal await get songs by title like that and we're gonna pass in search params dot title like that perfect and then just return hey Dev search like this and Export default search like that perfect and now you can go ahead and click on the search button right here and you should no longer get a 404 error instead you should get this search right here great so now let's go ahead and let's style this a little bit so I'm going to go ahead and give this a class name of BG Dash neutral 900 rounded Dash LG H dash full W Dash full overflow Dash hidden and overflow dash line Dash Auto as well great and now you can see how we have a nice little box here now inside of here I'm going to remove the search and I'm going to reuse our header component which you can import from add slash components header like that let's go ahead and I'm going to write search inside of that for now uh and you can see how that looks now much better but I want to give this a different styling so I'm going to give a class name of from Dash BG Dash neutral Dash 900 like that which is the same as our background meaning I don't want any gradient effect on the search page just to make it look different let's create a div inside and let's give it a class name of mb-2 flex Flex Dash call and GAP Dash y-6 like that and inside of that I'm going to create an H1 element and I'm going to write search like this and give that a class name Excel and font semi bold like that great now our search looks much bigger and better perfect and now what I want to do is I want to create a search input in here so go ahead and write search input like this and if you save of course you're gonna get an error because it does not exist yet so let's go into our components create a new file search input.bsx I'm gonna mark it as use client let's just quickly fix this so search input like that I'm going to return the div search input and I'm gonna go back into my search page.phsx and import this from add components search input like that and the uh the error should go away uh great now let's go ahead and let's add uh some hooks here so we're going to create a new hook called use the bounce uh that's because I don't want to refetch our songs on every single input we write so I want to add a bit of a delay so that when user stops typing that's when we're going to refresh the songs so for that go into Hooks and create a new file use debounce that DS like that so go ahead and import use effect and use state from react and then write a function use D bounce open curly brackets and write a t open parenthesis value is T delay is an optional number and it's going to return a t and then open uh the function like that great now let's go ahead and write const the bounced rebounced value set the bounced value is equal to use state and by default uh inside we're gonna pass in the value like that and the type is going to take is T like that great and now let's write a use effect so don't forget the dependency array here and we're going to create a timer so const timer is equal set timeout go ahead and just write set the bounced value to value and add a delay to this set timeout here like that or default it to 500 if delay has not been passed uh great and on return so on unmount we're gonna clear timeout timer like this so we don't have any overflow and in the dependency array just put value and delay like that perfect and you can return whoops you can just return the bounced value so what this is going to do is it's going to debounce our values so very simple when we start typing uh we're going to use this USD bounce to only get a result after 500 milliseconds of the user not typing anything that way we will not uh reuse our API calls and just go export default use the bounce like this and I'm just going to quickly expand this so you can see the whole code so use the bounce we set the state right here you create a timer here with a timeout of either a delay that we can pass and change every time or by default we use 500 milliseconds and on unmount we clear the timeout so there is no overflow great now that that is done we can go back into our search input component right here and let's go ahead and let's give it a couple of functionalities so const router first use router from next slash navigation like that launched value set value is equal to use state like this and you can import your state from react and give it a type of string like that and then constantly bounced value is equal use the bounce also accept a string and by default its value and we're going to pass in 500 milliseconds as well great uh now what I want to do is I want to install another package called query string so let's go ahead in our terminal and I'm going to write npm install query Dash string like this go ahead and run the project again and refresh your page if you've shut down the app and I'm going to import that so import Qs from query Dash string like that and I'm just going to move this to along with it great now let's go ahead and create use effect here inside first I'm going to create a query title is going to be the balanced value like that and then we're going to create a URL so const URL is equal to Qs that stringify URL go ahead and open URL to be slash search like that and query is going to be query like that and in the dependency array they're going to pass in the bounced value and the router and you're also going to have to do router.push URL like this at the end great so now that we have that we can just simply remove this div inside and instead we're going to render our input component which you can input but which you can import from dot slash input because they are in the same components folder right here you can see how now I have a nice little input component here and all we have to do is assign it the capital of props so placeholder is going to be what do you want to listen to question mark value is going to be value on change it's going to have an event and set value event.target.value like this great so now if you try and play with it and if I type in for example test you can see that uh after 500 milliseconds my URL got assigned the test value here great so now let's actually add some items here so we can uh start seeing our search results so go back into page.tsx um in your uh in your search folder right here and just below the header at a search content like this and pass in the songs songs like that you get the songs from get songs by title and of course we have an error because search content does not exist so to fix that we're gonna create a components folder inside of our search folder in the app folder so the same way we did with site and inside create a new file search content that ESX mark it as use client I'm gonna quickly fix this like this go back into page and just import that from dot slash components search content so not from the global components because it's not there it's right here great so you can see how it says search content in here now so let's actually go ahead and write an interface here so interface search content props songs is gonna be a song like that which is an array let's assign these props and let's extract songs like that perfect and first thing I want to write a special check here if there are no songs so if songs length is equal to zero we're gonna return a div with no songs bounce text and let's go ahead and give this a class name so we're going to write Flex Flex Dash call Gap Dash y-2 W fool px-6 and tax Dash neutral Dash 400 like that perfect so you can go ahead and write something OBS obscene and you can see uh how it's gonna say no songs found because we have nothing of this title in our uh database but if I remove it you can see how we are back to search content so if there are any songs instead of rendering search content we're gonna iterate over our songs so first let's go ahead and give this a class name full npx-6 like that and instead of that let's write songs.map uh we're gonna use the song like this and you're gonna immediately return a div we're going to give this div a key of song dot ID the class name is going to be Flex items Dash Center Gap Dash x-4 and W Dash full like this and inside I'm gonna create another div and just give it a class name of flex dash one like that and I'm going to use media uh item component which we created recently so make sure you import media item from add slash components media item and just pass in two properties so on click uh it's for now going to be an empty function and then data is going to be song like this perfect so now you can see how I have three songs right here and I just want to write a little comment here uh so I'm just gonna write this add like button here like that and I'm gonna prefix it with to do so I can search for it later so that's why we created this div with the flex uh so because next to it uh it's going to be a like button great so you can see how now I'm gonna try and search for deep stone and you can see how I only get this Stone if I remove it and back to all of this if I try all you can see how I got that if I try something uh different you can see what I get great uh so great great job uh all that's left is to create a liking functionality and then we're gonna load the songs in this light page right here and then we can actually enable our songs to be played so now let's go and let's create the favorites functionality so I want you to go back into the search page right here where we are going to add our liked button so let's go here where we wrote the comment to add the like button and let's actually do that so I'm going to write a component like button like this and I'm gonna pass in a prop song ID to be song dot ID like that and after we save of course we're gonna get an error because like button component does not exist so let's go and resolve that in components create a new file like button dot DSX like that so what I'm going to do here I'm going to mark it as use client like that and I'm gonna quickly fix uh this error so like button like this it's gonna have a div like button like that and I'm gonna go back into my search content and I'm going to import that from at slash components like button like this and I'm going to save and the error is gonna go away and you can see how I have the text like button on my right side so let's go ahead and add some interface to fix the typescript error so interface like button props inside I'm gonna put the song ID to be a type of string like this and then I'm gonna assign react.fc like button props like this perfect and inside I'm going to use the song ID like that and first things first let's go ahead and add the router so const router is equal to use router from next slash navigation like that below that I'm going to use the Super Bass client from use session context like that and you can import use a session context from add Super Bass slash out helpers react like this great and now I'm gonna go ahead and get my auth model so const model is equal use out model like that and you can import that from ad hooks use alt model like this and I'm also gonna need my user so user is equal to use user from at hooks slash user use user like that perfect so now that I have that I'm also gonna add a state here so const is like set is light your state false like this and go ahead and import use state from react I'm going to move it to the top with the package Imports great and now what I'm gonna do I'm going to create a use effect which is going to check whether the song that I'm currently loading has been liked or not so for that we're going to use this table right here that we created called uh liked songs right here so this is where we're gonna check if there is a song in this table with the current user ID and the current song ID that we're searching for so that's how we're gonna know whether uh a song is liked or not so let's go ahead and create a use effect like that and inside first I'm going to check if there is a user ID like that if there is not one I'm just going to break this function immediately great and now let's go ahead and create a function almost fetch data which is going to be an asynchronous function like this and what we're going to do here is we're gonna go and try and find a song in the liked songs table uh by the ID that we passed in here so const the structure the data and error from await Super Bass client dot ROM likes underscore songs like that dot select select an asterisk inside these equal user underscore ID to user dot ID and also song ID needs to be equal to song ID which we passed as a proc and we're going to choose a single uh property great like that and now what I want to do is I want to check if there was any error so if there is no error and if we have the data in that case set is liked to True like that perfect and we have to call this function so patch data here at the end of the use effect and in the dependency array put in the song ID Super Bass client and the user question mark ID like that perfect and now what I want to do is I want to dynamically render the icon depending on whether we are um uh whether we have liked the song or not so go ahead and write const icon with a capital I and and it's going to use is light question mark a I feel part so you can import AI feel hard from react Dash icon slash AI like this otherwise we're going to use AI outline part like that which you can also import from the very same package like this great so now I'm gonna go ahead and I'm actually going to create a uh a button here so let's go ahead and replace this with button like that and let's use the icon element inside which we just created here let's give it a color which is going to be dynamic so if we have liked it in that case is going to be hashtag 22c55e otherwise it's going to be white and a size is going to be 25 like that great so you can see how now I have a heart icon here and none all of them are white and outlined because we have not favorited any songs yet and let's just give some class names to this button to make it look a little bit nicer so cursor is going to be pointer actually we didn't have that it's a button so hover opacity 75 and transition so just to make it a little bit more interactive so it kind of Fades when we hover on it great and I also want to add in on click handle like and we're going to create that right now so let's go ahead and write a const handle like like this and first let's check if we have the user or not so if there is no user in that case we're going to return Alf model on open like this so it's important that you return this so it doesn't try to do any of the code that we're gonna write after so what this ensures that if we are logged out and we try to like it it's going to open the authentication model the same way with our upload model great so now let's go ahead and let's define what happens if we already like the song and uh what happens if we haven't so if we already like the song So if it's a light in that case let's go ahead and extract the error from here await Super Bass client ROM likes to underscore songs like that dot delete the song which has an equal user ID to user dot ID and it has an equal song underscore ID to song ID like that perfect now also make sure to make this an asynchronous function whoops like this so we can safely use a weight so handle light should be asynchronous great now let's go ahead and check if there was an error so if there was an error in that case we're going to use toast and you can import toast from react hot toast like this I'm going to move it along with the other inputs like that all right those dot error error Dot message like this great and else I'm gonna manually change set is light to false great and now we're gonna go to the end of this uh if it's liked so go to the end and right else in that case we're not going to delete it from the table but we're gonna insert it into the table so again const error await Super Bass client like that ROM likes underscore songs dot insert song underscore ID is the song ID and the user underscore ID is the user dot ID like that great and make sure you put a comma after the song ID so you don't have an error now let's check if there was an error wait while doing this so if there is an error in that case those that error error that message again else set is unlike is going to be too true like that and we're also going to trigger a toaster success with a light like that great and at the end of that all I want to call router.refresh like that perfect so now let's go ahead and let's try uh if this works so I I I recommend you have this open so have the light songs table ready and try and click on a like and you can see how I successfully changed it here but let's see if that actually works in a database and it does so you can see that it has mixed my user ID with the song ID that I liked and if I click again it has been removed from the database perfect so that is exactly what we want you can see how nice this looks great and now what I want to do is I want to create the light songs view right here so let's go ahead and let's do that so first thing I want to do is to create an action which is going to be able to fetch the light songs from the currently logged in user so let's go ahead I'm going to expand this a little bit I'm going to expand my sidebar here I'm going to collapse everything and go in my actions I'm going to copy get songs and paste it and I'm going to rename it to get liked songs like that and just rename the function inside as well get like songs like that perfect and now we also have to get the session so const data session await super bass at all that get session like that so now we have this session inside uh and what I'm going to do is instead of fetching it like this so we're gonna fetch it from like underscore songs we're gonna select everything but I also want to uh populate the relation that we have because if you look at our like songs ID um our uh second key which is the songs has a relation to public songs ID so we want to fetch that entire song that we are aiming at so add a comma here write the songs and open parenthesis and inside select everything like that and the ones we're going to select are the ones that are equal to user ID which is the session question mark dot user question mark dot ID like that perfect so we are only going to fetch light songs from our currently logged in user great and what I want to do now so yes if there was an error uh return uh console error and return an empty array like that uh if there is no data in that case return an empty array as well otherwise we're gonna not gonna return it like this we're gonna have to modify it a little bit since we're working with the relation here so data.map item like this go ahead and open an immediate object and you're just going to return item dot songs like this now I know this sounds confusing it sounds like we're spreading an array but we are not we're actually just spreading a relation which we have populated with this one song that we will be loading in each of these fields great so that is exactly uh what we want so let's go ahead and let's actually create our page called liked like that and inside create a new file page.tsx liked liked songs like that and now that you have this page you can safely click on this light songs here and it should redirect you to slash light or you can manually go to slash light and you can see the content uh liked songs like that great so now let's go ahead and let's just add the uh expert cons to revalidate is equal to zero and one place where we forgot to add this was in our search page so go back to your search page into page.dsx and just add this here as well so it's not cached great now you can go back into your liked page.dsx and let's start developing here so first make this an asynchronous function here and let's get our song So const songs is equal await get liked songs from ad slash actions get liked songs like this perfect and now let's go ahead and modify this a little bit so I'm not I'm going to remove this like songs here I'm gonna give this a class name of BG Dash neutral Dash 900 rounded Dash LG H dash full W Dash full overflow Dash hidden and overflow Dash Y dash Auto like that great and inside I'm going to reuse our header component like this so let's just go ahead and import ad components slash header like that so that's going to bring our navigation and our uh and uh some other stuff here great and now inside there create a new div and let's give this a class name of empty-20 like that and inside create another div with the following class names Flex Flex Dash call MD flat stash row items Dash Center and GAP Dash x dash five like that so we are preparing for mobile view here as well great now inside of that div create a new div and give it a class name of the following relative h-32w-32 LG h-44 and LG w-44 as well and inside we're going to use an image component from next slash image so make sure you've imported that I'm going to move it to the top since it is a package import great it's a self-closing tab and let's give it a fill attribute let's give it a source of Slash Images slash like dot PNG like that let's give it an out of playlist like that and let's give the class name of object dash cover like this great and now after we've done that image let's go outside of this div that's wrapping the image and create a new one and this one create a class name and put inside Flex Flex Dash call Gap Dash y-2 mt-4 MD md-0 like that and create a paragraph inside which is going to say playlist like this and it's going to be a very small text so it's going to be hidden on mobile actually and it's going to be visible uh on the on medium devices Font Are semi bold and text SM like this great and below that we're going to go ahead and create a heading like this Marina I'm gonna say like songs like that so it's going to be a bit bigger and let's go ahead and give it some class names so we're going to go ahead and give it a text Dash White tax dash for Excel SM tax Dash 5xl LG text-7 XL and font Dash bold like that perfect so you can see how that looks and you can go ahead and stretch your device to see how uh the text is much larger on the desktop and you can see how on mobile it collapsed in a column so that's exactly uh what we wanted to do great so now let's create the content to load the songs actually so go ahead and find the end of your header and we're going to create a new component called liked content like that and we're gonna pass in songs like this so of course if you say we're going to get an error so inside this liked folder create a new folder called components and go ahead and create a file liked content dot PSX like that Mark it as use client and let's just quickly fix this error so I'm just gonna write in div light content like that I'm gonna go back into my pages into my liked photo folder page.tsx and I'm going to import this from dot slash components like the content like this perfect so now let's actually go ahead and let's edit this so it looks so it actually renders our songs so first let's go ahead and write the interface so interface like content props is going to accept songs which is a type of song which you can import from types and make sure you put a array at the end react.fc is going to be like content props and extract the songs from it perfect so now let's go ahead and add a router second router is equal to use router like that from next slash navigation so I'm just going to move that to the top because I like to separate my imports and let's also get the user so const is loading user use user like this and you can import use user from add slash hooks use users who don't accidentally import the Super Bass one great and now that we have that let's create a news effect which you can import from react right here and in this use effect we're going to redirect the user from this website if we are not logged in so if it's not loading and if there is no user in that case router that we place and we're gonna go to slash like that and just passing is loading user and router so I just want to ensure that only authenticated users think can go to slash Lite so if you log out you can get redirected back to the home page great so after we have that let's create a view if there is no light song so if songs length is equal to zero in that case return a div the class name of the following classes my apologies I disconnected my keyboard all right so Plex Flex Dash call Gap Dash y-2 W Dash full px-6 and text neutral Dash 400 like that perfect and inside we're gonna write no liked songs like this so if I go ahead and try I'm gonna go into my search and I'm gonna remove the likes from test and remove the likes from so basically make sure you have not liked anything and go back into your liked and you can see how it says no liked songs great so now just uh to make this visible light at least one song two songs so you can see something rendered uh in this slash light so go back to slash light and let's go ahead and let's actually render these items here so I'm gonna give this a class name of flex Flex slash call Gap Dash y-2 W full np-6 like that and inside I'm going to go over songs.map I'm gonna get a song and I'm going to render a div I'm going to give this deep a key of song dot ID like that and a class name Flex items Dash Center gap-x-4 and W Dash full like that and inside I'm going to open another div and give this a class name of flex-1 and inside of that div I'm going to put the media item component and you can import the media item component from add slash components media item go ahead and pass in the on click which for now is just going to be an empty function and later uh it's going to play a song and pass in the data which is the song Android you can see how we now render our liked songs in here and one thing I want to add here is so just uh outside of this div which has Flex one go ahead and add the like button which you can import from add slash components like button and don't forget to pass in the song ID which is song dot ID like that great so you can see how now we've finished our light songs and if I click on here you can see how it removes itself from like songs but if I go to search and maybe like this and then go back you can see how I am here again great and I can remove it I can remove all of them and I have a message that there is no light songs great so we finished liking our songs and now it's time to actually create a player which is going to be able to play these songs great job so now let's go ahead and let's create our player component which is going to dynamically appear at the bottom of our screen every time a song is playing and it's also going to be capable of playing songs in a playlist for example if I select a song from this newest songs it's gonna play between these three songs if I select it between these ones it's gonna play between the library and same thing if I select one from liked songs or if I search for example uh for something like this it's only gonna play this one on repeat so it's gonna be a very smart player which is going to detect where we click to play the song and that's how it's Gonna Run them in a playlist great so we're going to start by creating a used player store so let's go ahead I'm gonna expand my code here a little bit and I'm going to close everything I'm gonna go into Hooks and I'm gonna create a new file use player.ds like that so first let's create an interface layer store like that it's gonna have IDs which is an array of strings like that it's going to have an active ID which is an optional string like this it's going to have a function set ID which accepts the ID which is a type of string and returns a void is going to have set IDs which accepts IDs which is an array of strings like that and returns a void as well and a reset which just returns a void like that great and now we're gonna go ahead and write const use player is equal to create from to stand so make sure you import create from to stand here and we're gonna pass in the store so player store like that and then I'm gonna go ahead and open my parenthesis I'm going to open the parenthesis again and I'm going to extract the set function from it and I'm going to go ahead and open an arrow function but I'm going to immediately return an object so open parenthesis and open an object inside and just press enter let's give it IDs by D default is going to be an empty array active ID by default is going to be undefined like that so set ID is going to be a function which accepts an ID which is a type of string and it uses the set function opens an object and assigns the active ID to that ID and then we're going to have set IDs which accepts an array of IDs which are strings and it also uses the set function to set the IDS to IDs like that and we're going to have the reset function which is just a void which uses the set function as well and just resets the state so it turns the IDS to an empty array an active ID to undefined so this is how we're gonna add our playlist functionality every time we click on play we're gonna set a list of IDs which are going to play in a playlist and the current clicked ID which is going to be played and from where the playlist is going to start and Export default use player like that great and now let's go in our app folder in our layout that ESX right here and just below this sidebar I want to add a new component called player like this and if you save of course we're going to get an error because player does not exist so go into your components and create a new file player.dsx like that marketers use client component and go ahead and create the player component like that so we can quickly fix the error player like this and go back into layout and just import that from add slash components slash player like this and once you save the error should go away great so now at the bottom if you scroll you can see a small text which says player so let's go into that player component and let's go ahead and add some hooks here so first const player is going to be use player from ad slash hooks use player like that what we have to do next is we have to find a way to fetch the song using the ID which is assigned in this player store as an active ID but there is a problem here so we are using Hooks and we have a client component but all the all the things so far all the ways so far we fetched songs was using server components so we use this create server component client so how do we create how do we fetch something from the client component well that's the great thing about Super Bass so it allows its SDK it's very powerful and it allows us a bunch of ways to fetch data so if we wanted to we could have completely avoid server component clients if we wanted to we could have fetched everything on the client but I didn't want to do that I would I would rather mix and match where we need exactly what so let's go ahead and let's create a new hook in here called use get song by id.ds so this is going to be used in the client it's going to be a hook so let's go ahead and write const use get a song by ID it accepts a parameter an optional string of which is ID like that and inside we're gonna set the is loading and set is loading like that to use state from react and by default it's going to be false like this great then we're gonna get the song second song Set song new state go ahead and give it a type of song which you can import from types like this or it can be undefined like that because by default it's going to be undefined great and now extract the Super Bass client from use session context like this and you can import use session context from add slash superbase out helpers react like that great now that we have that let's go ahead and create our use effect so first thing I'm going to do I'm going to check if ID was not passed in that case I'm going to break the entire function no need to do anything further otherwise set is loading to true because what we're gonna do is we're gonna fetch a song so const fetch a song is going to be an asynchronous function like this in which we're going to get the data and error from a weight super based client Dot from we're going to Target the songs table we're gonna select everything uh where the ID is equivalent to the ID passed and we're going to mark it as single because we only want one record now we're gonna check if there was an error so if there was an error set is loading it's going to get to false and return Coast which you can import from react hot toast like this dot error error Dot message like that great and now if that was not the case we're gonna say set song data as song like that and set is loading to false perfect and just remember to call the fascia song function at the end of your eu's effect here and in the dependency array go ahead and add ID and Super Bass uh whoops Super Bass client like that perfect so now that we have that we can safely return a use memo so we can safely memorize things if we need them from this hook we're gonna return is loading oh yes so change this a little bit so we're not going to return an arrow function we're going to return an immediate object so open parenthesis and then an object so we can safely return this loading and song and pass in is loading and song inside of that great and remember to export default use uh get song by ID like that uh perfect so now that we have that we can go back into our player.dsx and let's extract the song from Muse get song by ID and we're gonna pass in player.active ID if there is one great now that we have that we have to find a way to load this song MP3 file from our storage which we have right here so if you remember we can do that by reading in our songs by reading the song path right here so that's what we're gonna do so the same thing we did we created the hook to load the image we're going to do the same thing to load the song So con song URL is going to be use load song uh song URL and we're gonna pass in the song like that so let's go ahead and create this so go into your hooks name it use load song url.ds like that and let's go inside and let's write const use load song It's Gonna accept the song which is a type of song you can import that from types and we're gonna write cons Super Bass client is equal to use super bass client and you can import use a Super Bass client from at Super Bass slash out helpers react like that if there is no song we're just going to return an empty string otherwise we're gonna get const song data so remap it so it's more readable Super Bass client storage from songs get public URL song whoops not a string so song Dot Song underscore path like that and return uh the song data.public URL like that perfect uh and I made a typo here so super bass client like this great and Export default use load song great so why am I using a used Super Bass client here but here I used use session context well uh in our case we can almost everywhere use the use super bass client but the more correct way to be would be to use this huge session context and then read the super based client from it so we only initialize this EU superbase client once and if you uh for example everything we read in our page so when we fetch the songs when we fetch the likes when we uh fetch uh URLs from Storage all of that has read access for everyone both authenticated and unauthenticated but if you were to change something in Super Bass and made it so that only authenticated users can even see the songs which are on the page in that case you would want to use use session com context so your supervised client has authentication in it but in our case we don't need that here so if you want you can use use session context like this and just extract the super based client from it but it's gonna not do it's not gonna do much change but if you're actually having problems you can go ahead and try with use session context if you've changed some authentication stuff great so now that we have that we can go back into our player and we can import this hook so let's just see if we made a mistake so use load song URL yes rename the hook to use song URL make sure the file is the same name and then go back into player and let's get that from here so use load song URL perfect and now that we have that so yes we have an arrow here because there is a chance that song is undefined so I want to fix that by just pasting in an exclamation point like this great and now let's go ahead and write an if Clause so if there is no song or if there is no song URL or if there is no player that active ID in that case just return now like that great otherwise what we're gonna do is we're going to give this div a class name like this fixed bottom Dash 0 BG Dash black W Dash full P Y dash 2 H dash open uh square brackets 80 pixels like that and PX Dash four so just for now I'm gonna comment this out like this so you can see how this looks you can see you should have a big uh black box here at the bottom uh which renders this player text right here and now we can uncomment this back so basically this is a protection that we don't want to load the player if we don't have the song If we don't have the song URL and if we don't have uh the active ID set so that's what I'm gonna do now I'm gonna enable a way that when we press on a song we actually add something to our use player here so let's go ahead and create that so we can uh properly develop our player component so to do that we have to create another hook first so I'm going to close everything here I'm going to go into my Hooks and I'm going to create a new file use on play.ts like that and I'm gonna write const use on Play It's Gonna accept songs which is an array of this song type which you can import from types like that and it's gonna get the player so use player from dot slash player because we are in the hooks folder like that it's gonna get the out models the const out model use power model also from dot slash and cons Destructor user use user from dot Slash use user and make sure you execute that great and now we're going to write const on play is equal to ID which is a type of string like this if there is no user we're gonna return out model that's on open like that so it's very important to return this otherwise even your non-logged in user and not subscribed users will be able to play music so make sure you return this and then player.set ID is going to be the ID and player that set IDs is gonna be songs.map a song song dot ID like this so what we're going to do basically we're going to create this reusable hook and we're going to place it in a bunch of these places so that every time we click the on play we're gonna play the current ID that the user clicked on but we're also going to create a playlist out of all the songs where where user clicked so that's what I explained if we clicked play inside of light songs we're gonna create a playlist of those like songs if we click play in this Library we're only gonna create a playlist of these three songs same thing on search even if we've written something where and only two results show map only two results show up we're only going to play those two songs I think that's a really cool feature great and what we want to do now is just return on play like that and remember to export default use on play like that great so now that we have that what I want you to do is I want you to go into the app folder into site components page content in the dxx and see where we have this empty on click function where we're going to change that now so let's go ahead and just above this if close right const on play is equal use on play which you can import from add slash hooks use on play and it expects an argument of songs and we have it right here so that's how we are going to create the playlist and then we're gonna use this on play to just call this um a song right here so on this on click you can see that it gives us an ID so go ahead and write ID which is a type of string and we're just going to call on play and pass it an ID perfect so now if I go ahead and click here you can see that my player opened so I'm going to refresh again there is no player active now but when I click on something you can see that my player has opened that's because we successfully loaded the song URL we successfully loaded the song and we have something in our player store great so now you can go back into your player.dsx file and now we can continue developing inside of here so I'm going to create a new component here called player content like that and I'm gonna give it uh a song song and song URL song URL and one very very important thing I'm gonna put here is the key attribute and the key is going to be song URL now you might be wondering why am I using a key and I'm not inside of an array usually we only use keys because we're using a DOT map function well one thing you might not know about the key attribute is that whenever it changes it completely destroys the element that was using it and re-renders it render as a completely new element the only reason I want to do this is because we're going to use playlist and we're going to enable users to skip to the next song so I want to ensure that the player component is practically destroyed before loading the new song that's because the hook which we are going to use to load the songs sorry to play the song unfortunately does not support Dynamic and modular URL changes so we have to create this little trick to reset that entire hook which is going to be used inside of this player content so that's why we assign this key so just make sure you have you've assigned this otherwise you're gonna have problems loading next songs they're gonna overlap or they're not gonna be able to load at all great if I save this file of course I'm going to get uh I'm going to get an error because player content does not exist actually it's only when I click but I'm going to get an error so let's go ahead and resolve that go into components and create a new file player content dot DSX like this Mark this as use client and let's just quickly fix the error so player content like that Dev player content go back into player.dsx and import that from dot slash player content like this and now if you try and click on something you're not gonna get an error you're gonna have the text player content here great so now let's go ahead and let's create an interface so interface player content props is going to accept song which is a type of song from types and song URL which is a type of string like this so let's go ahead and assign that react.fc uh player content props and you can just extract those so song and song URL great and now what we're gonna do we're gonna create basically this is going to be the component which is going to control uh a display of the currently playing song uh the controls to play and pause and the volume and the actual functionality of playing the song great so let's go ahead and I just want to give it a couple of styles uh before we start writing the main functionality so let's go ahead and give this div a class name so class name it's going to be grid grid Dash calls and the grid Dash course Dash three and H dash full like that inside of here I'm going to remove the player content and I'm going to create a new div with a class name of flex W Dash full and justify Dash start like that and inside of that I'm going to create a new div with the class name Flex items Dash Center and get Dash x-4 and inside of that div I'm gonna put in a media item which you can import from dot slash media item because we are in the components folder and a like button you can import that as well from dot slash like button and don't forget to put this give this a data of song and give this a song ID of song dot ID like that so now when I click on this you can see how I loaded the current song here and you can see I can even like it from here and it's going to appear uh in my favorites here and if I remove it from here it's going to be removed from here very cool so we reused a bunch of components that we created great so what I want to do now is I want to go outside of this div right here and I want to create a new div and I'm going to give it a class name of flex MD hidden so this is only going to be visible on mobile so I suggest that you collapse your screen to mobile like this so MD hidden call Dash Auto W Dash full justify Dash and and items Dash Center like that and inside we're gonna create another div component we're gonna give it an on click for now it's going to be an empty function and give it a class name of the following so it's going to have a class name of h-10 w-10 flex items Dash Center justify Dash Center rounded Dash full BG Dash white p-1 and cursor Dash pointer like this and inside we're going to put the icon of course we don't have the icon yet so let's go ahead and quickly uh create that component so I'm gonna go here to the top and I'm going to write const icon with a capital I and for now I'm going to hard code this so I'm just going to say true question mark BS pause fill you can import this from react icons so import BS pause fill from react Dash icons slash ES otherwise BS Play Bill you can also import that from react icons great uh all right so now that that is done uh okay it seems like we made a mistake because our button is visible but it's uh all the way down for some reason so let's just quickly see what we did wrong all right so what we did wrong was in this main uh grid right here so go to the top and instead of grid Dash calls give it the grid Dash calls two like that and then you should have a nice little circle here great so go ahead and find this icon which we added uh right here give it a size of 30 and a class name of text Dash black like this great so now you can see how by default uh it's in a in a playing state so that's because I hard coded this if I change this to false you can see how it becomes in a playing State great so you can leave it to true or false however you wanted we're gonna later make it Dynamic so now let's go ahead and extend this so we are in the desktop view so your button should go away now so that's what we created here that was this component right here and now we're gonna go ahead uh go below that and we're going to create a desktop view for our controller for our player so create a div right here and give this a class name of hidden H dash pool MD Plex justify Dash center items Dash Center W Dash pull like this Max Dash W Dash 722 pixels and GAP Dash X-6 like this great now inside of that I'm first gonna add the icon to go backwards so a I fill step backward like that and you can import AI field step backwards from react Dash icons slash AI like that it's a self-closing tag like this and you can see how it appeared in the middle of my screen right here let's go ahead and let's give it a size of 30 and let's give it the class name of text Dash neutral Dash 400 cursor Dash pointer hover text Dash white and transition like that and we're also going to give it an on click for now it's going to be empty like that great so after this we're going to create a div here uh and inside uh we're gonna add another play button so let's go ahead and write on click here which again is going to be empty for now let's give it some class names so let's go ahead and write Flex items Dash Center justify Dash Center H dash 10 W dash 10 rounded Dash full BG Dash white p dash one and cursor Dash pointer like that and inside again we're gonna put in an icon uh we don't import that that is dynamic so the same way we did for mobile uh here great so let's give it a size of 30 and class name of text Dash black like this uh perfect and now after that div we have to create another icon AI feel step forward like that it's also a safe closing tag and I imported it from the same way I did AI fill step backwards from react Dash icons AI great and now right on click here also give it an empty function uh size is going to be 30 like that and class name here is going to be text Dash neutral Dash 400 cursor Dash pointer hover text Dash white and transition great so now you can see in the middle of my um in the middle of my uh screen in my player I have this controls right here and later on they're gonna play a song and move on to the next song Etc Great so now let's go uh and find the end of the div that wraps this controls that is this div right here or technically you can go uh uh technically you can go and find the last div right here and just go here like that and go ahead and write another div here and write class name hidden and the flex W Dash full justify Dash end and PR Dash two like that go inside and create another div with the class name of flex items Dash Center Gap Dash X-2 and W Dash open square brackets 120 pixels like that and here we're going to use the volume icon volume icon is also not something you can import instead it's something we have to create so const volume icon is equal again I'm going to hard code true question mark hi speaker uh x mark like this and go ahead and import that so import hi speaker x mark from react Dash icon slash hi like that uh let me just see okay it's not slash h i e slash H I2 like that and otherwise it's going to be hi speaker wave like that which you can also import from react Dash icon slash H I2 and now we have that volume icon here great uh and you can see how now my volume is muted by default so let's go ahead and work on the styling of that a little bit so this is also going to be able to mute things so on click for now it's going to be empty later it's going to be able to mute uh class name cursor Dash pointer and size is going to be 34 like that so it's a bit larger great and now what I want to do uh besides that I want to give it a slider component so we're going to go ahead and create a slider component using Radix so just below the volume I can go ahead and write slider like this and of course we're going to get an error because slider does not exist so go into your components create a new file slider.dsx like here the market as use client now let's just quick quickly fix this so I'm going to name this slider and I'm going to return a div which says slider go back into player content and import this from dot slash slider the same way did with like button and media item and just click on something so your player appears and you can see how we have the slider right here great now let's go into the slider right here and let's import Asterix meaning all as Radix slider from at Radix Dash UI slash react slider so obviously we have to install that package let's go into the terminal I'm going to expand everything a little bit and I'm going to write npm install at radix-ui slash react slider and I'm going to press enter and just wait a couple of seconds for this to install and then we can refresh our page so npm run Dev again I'm going to refresh my localhost like this make sure you are in desktop view so you can see all of this and now let's go ahead and write an interface for this so interface slider props is going to accept value which is an optional number and on change is going to be optional and it's going to accept the value which is number and returns a void like this and now let's go ahead and add react.fc slider props like that and let's extract value and on change like this great and by default let's give it a value of one great now let's write the handle change function so const handle change is equal to new value which is a type of number and it is actually an array because slider from Radix can have multiple points but we are only going to get work with a single point but we still need to apply the proper types so the value in handle change which we're gonna use is going to be an array of numbers and what we're going to do is call on change question mark dot open parenthesis new value the first value like that great now that we have that let's remove this and let's actually write Radix slider that root like this great and let's go ahead and give this slider some class names so I just want to open this keep this open so you can see what you're developing so class name is going to be relative Plex items Dash Center select Dash none touch Dash none W Dash full and H dash 10 like that great now let's go ahead and give it some values so default value again the value is an array so open an array and give it a default value of 1 like that and then give it a value prop again an array which accepts the value prop which we have on value change is going to call the handle change like that Max is going to be 1 and step is going to be 0.1 and we're going to add an area Dash label volume like this because we're only going to use this slider once great and now inside of that let's go ahead and add radixslider dot tracks like this and for that we're gonna give it a class name uh BG Dash neutral Dash 600 like that relative grow rounded Dash full and H dash open square brackets three pixels like that perfect and inside of that you can see how a small range has appeared here with the darkened color and inside of that right Radix slider that range like this actually it's a self-closing tag so you can just write uh like that give it a class name of absolute BG Dash white rounded Dash full and H dash full as well great so you can see uh we're gonna try and give it some values there and then you can see how we're going to be able to change this using our Mouse uh great so we completed our slider component here now let's go back into player content and we are actually ready um we are ready to add some uh actual functions here so I'm going to go to the top where my uh volume icons are right here and first things first I'm gonna get my player so const player is equal use player which you can import from at slash hooks Slash use player like this go ahead and execute that function right here then create a state for volume and set volume like that use state by default is going to be one and make sure you import your state from react I'm gonna go ahead and put that to the top right here great and now I'm going to modify this volume icon to use the volume is equal to zero in that case we're gonna display uh the mute Mark otherwise we're gonna display what it looks like now uh like not muted and create another state here is playing set is playing you state again and by default is going to be false and then we're going to replace this hard-coded true with this is playing and now you can see it looks like it's ready to be clicked uh great now let's go ahead and let's create our own play next function so const on play next is an arrow function we're gonna check if uh there is an array if there is an active array of songs to play so player.ids that length is equal to zero in that case we can just break the function otherwise first let's find the current index of the song that's playing so we can play the next song aligned to it so const current index is equal to player dot IDs that find index like that ID open an arrow function ID is equal to player DOT active ID like that so I'm just going to expand this so you can see the entire function const current index is equal to player IDs find index and we compare it to the active ID playing and then let's define the next song so const next song to play is going to be player.ids open an array current index plus one so now what's important is to check whether there is a next song because there is a chance that the song we want to play is the last in the array so if there is no next song in that case we're gonna return player.set ID layer dot IDs zero so if our song is the last one in the array and we press next we want to reset the entire playlist by playing the first song otherwise player.set ID next song like that so now we have the on play next and we can actually go ahead and find so not a I feel backward but a I feel forward so make sure you find the AI field step forward and replace this empty function with on play next like that great now let's go ahead and copy this entire thing and rename this one to on play previous like that so we have the same check at the beginning check if there even is an array great and how we're gonna choose the next song well we're not going to choose the next song let's rename this to previous song like that and instead of looking for the next one we have to use the minus to look at the song before the one that's currently playing and then just replace this next song here and next song here and one more thing what if the song we are currently playing is the first in the array and we click on play previous song well we don't want to load the same one again what we want to do is load the last song in the array so player.ids.length minus one like this so this is going to load the last song because we're on the first song and we want to go backwards so the user experience that's good is that we load the very last song from the array at least that's what most popular streaming services do so now we have the on play previous so let's go back and let's find AI fill step backward and let's assign that to this empty function right here great perfect great job and now what we're gonna do we're gonna finally play some songs so for that we're gonna need a hook use sound so go into the terminal and the right npm install use Dash sound like that so wait a couple of seconds for this to install and npm run Dev again great I'm going to refresh my entire page and now we are ready to actually add that hook here so let's go ahead and let's write const open an array is equal to use play Sorry use sound and you can import that from use Dash sound which we just installed right so go back to use sound and here in this array the first thing we're gonna destructure is the play function and in the second one we're going to open an object and get the pause and sound like that great now go ahead and open parenthesis to this EOS sound and in the first argument you're going to give it a song URL which we already fetched in the player component so we fetch that right here and then we pass it to display our content so that's what I was talking about so this song URL unfortunately cannot change dynamically so when we go to the next song or the previous song the song URL is going to change but this hook does not work like that so unfortunately it won't work so that's why we use the key attribute here to destroy this entire component and reload it and get the new song URL and then this Hook is going to behave exactly as we wanted to great and for the second argument open an object here and add the volume to the volume so that's how we can control the volume great and then below that you're gonna add the on play make sure you don't accidentally write on play like this so it's all a lowercase like this all play is a arrow function which just turns the set is playing to True like that then on end is an arrow function which is set is playing to false and immediately play the next song so on play uh sorry on play next like this great and on pause again all lowercase all it does is set is playing to false like that and now a very important attribute you have to add here otherwise your songs will not be playing format needs to be an array of MP3 if you do not put this you will not hear your songs so it's very important that you put that great and now that you have that uh first thing I want to do is I want to create a use effect that's going to automatically Play the song when the player component loads because of the way our player is built that's what we want so use effect you can import use effect from react right here write an arrow function here and just write sound question mark dot play because there is a chance it doesn't exist and then return sound question mark dot unload like that and in the dependency array just put this sound like that great and now let's create the handle play function so const handle play like this if is playing in that case play sorry if exclamation point is playing so if we are not playing go ahead and turn on the song else pause the song like that great and one last function we're gonna write is the toggle mute so const toggle mute like this if volume is equal to zero in that case set volume to one otherwise set volume to zero like that perfect so let's assign this toggle mute to this volume right here great and also we have to add some props to this slider so let's go ahead and write value to be volume and on Change is Going to Be an Arrow function which gets the value and calls set volume and gives it a value like that so I'm gonna expand my uh view right here and if you try and click play you should get a song playing I'm not gonna play any songs because of copyright so I'm just gonna test this privately whether it works or not great so it works for me it takes a couple of seconds to load the song but it definitely works for me uh all right so what I want to do now is uh I'm just gonna be muted here all right uh and I wanna add this function handle play to our to play buttons so we have two play buttons first one wherever you have this uh Dynamic icon go ahead and find the empty Arrow function and replace it with handle play this is for the mobile view and one is in between the uh steps so right here go ahead and replace that with handle play as well great so now if I go ahead and click here you can see uh it's loading the song it's loading the song and now it started playing it so that's how I know that it's playing and I can of course I I heard it before but I don't wanna put any songs in my video because of copyright and you can go ahead and test the volume as well you can also click to mute it completely or click again to unmuted amazing amazing job you have a working player but there is still a couple of things we have to do one of them is we have to move this main content that we have here just above our player great so let's go ahead and do that and then we have to add the same play functionality to this sidebar to the light songs and to the search so let's go ahead and do that now so let's go ahead and let's go into our sidebar component so find the sidebar component like this and we're going to change this main class here to be dynamic depending on whether we've opened the player uh or not so for that we're going to need to use the player hook here so const player is equal to us player you can import that from add slash hooks Slash use player like that great now that you have that you're gonna go ahead and you're gonna replace uh this initial string right here with an object and write TV merge and you can import TW merge from Tailwind Dash merge like this so go ahead and just do that open uh parenthesis I'm going to use template little strings you can use normal strings and inside I'm going to write Flex H dash full so the same thing that was here before and then I'm gonna give it a comma and I'm going to write player.active ID and and H dash open square brackets calc so calculate a hundred percent minus 80 pixels make sure you don't accidentally put spaces like this so it needs to be all in one line and if you have the extension Tailwind CSS intellid sense uh then you can confirm that it's correct great so now I'm going to refresh and you can see it's very hard to notice it's a subtle effect but if you had enough songs that would fill the entire screen where you would have to scroll now they would not get hidden by this player rights here so you can see how my screen here takes the entire how my box is here take the entire screen but once I click play they kind of move for 80 pixels up which is exactly what I wanted great and now what we have to do is again we have to add display functionality let's go and let's add it to the Side Library first so go ahead and find your library like this and what you're gonna do here after this use user go ahead and write const on play is equal to use on play and you can import that from at slash hooks Slash use on play and go ahead and pass in all the songs that are in this playlist and now that you have this on play go ahead all the way to the bottom where we iterate over media items and replace this empty array with an ID string like that and just run on play ID like that so I'm going to refresh here and if I click here for example there we go the same thing happens we can now play songs and yes of course go ahead and try if you can uh go forward or backwards with your song so you can see how they correctly go in order and they reset the entire array great uh and now what we have to do is we have to do the same thing uh in our search components so let's go ahead and let's go into a search content actually so go ahead and find the search content like this again we have an empty array here sorry an empty function here so let's go to the top right here and just add const on play is equal to use on play you can import that from hooks use on play and pass in the songs so it can create a playlist out of the currently playing songs then replace this with an ID which is a type of string and just call the on play and pass in the ID like that so I'm gonna try that here there we go the same thing happens so I can go in a playlist like this I can click on individual ones amazing and one more place where we have to do this is in our liked songs so let's go ahead and let's actually find our liked content so go like the content like this again we have an empty function here I'm gonna go to the top of my liked content and after loading the user I'm gonna write const on play easy we'll use on play from hooks use on play and pass in the songs so you can create a playlist out of your favorite songs and instead of an empty Arrow function this one takes a string like this and calls on play and passes in the ID so I'm gonna go ahead and test this I'm gonna like this song and this song I'm gonna go back to light songs I'm gonna click on deep Stone and the next song that will play is test and the next one that plays is deep Stone so exactly as I've explained that it works so great great job you've finished all the main functionalities of a Spotify clone so there is a reason I wanted to leave stripe last and that is because it is by far the most complicated part of this entire project so even if you run into some issues with stripe or for some reason don't manage to implement it I still I'm still very happy that you've come this far because you have a fully working Spotify clone which can play music I can create playlists you can upload songs a bunch of stuff you also have the uh the favorites functionality so amazing amazing job so far all that's left is it's to create these strike payments which is a complicated part but you've done an amazing job so far great great job so before we move on to stripe I just want to add the loading and error handling in our app right here so I'm gonna go here and I'm going to close everything and I'm gonna go uh and in this root folder I'm gonna sorry in the app folder I'm going to create a new file called error.dsx like this it's going to be a used client component that's very important and all I'm gonna do for now is write const error like this and I'm just going to return a div which says error like that and make sure you export default error like this just make sure you don't misspell it and then this should refresh and nothing should uh go bad great and I'm going to reuse my box component which we had created at the beginning of the tutorial here and uh inside I'm gonna give it a class name of H dash full blacks items Center and justify Dash Center like that and inside I'm going to go ahead and open another div we're going to say something went wrong like this and give it the class name of the x dash neutral Dash 400 like that great and now I'm gonna go try I'm gonna go in the layout.dsx and in here I'm going to throw new error test like this so we're going to take a look uh at how that looks uh let's just see okay it says unhandled time there uh okay uh so we actually also have to put it inside of the page for it to properly work so this is what I wanted to do I wanted to move it in the page folder and I wanted to throw the error inside the page here so let's go ahead and try that throw new error best and now we should have yeah there we go this is what I wanted to display so now you can see how when I move the error.dsx inside this site folder I forgot that we moved that page there uh you can see how the error is handled nicely so if there was an error that happens in this get songs uh for any reason and we don't catch it we're gonna have a nice little handle for that here uh great and besides the error inside I also want to have a loading.dsx so let's go ahead and let's also do the loading so loading is going to be used client as well const loading like this and let's just return a box again which will say loading like this just to fix the error and expert default loading like that uh and the box is also going to have a class name of H dash full Flex items Dash Center and justify Dash Center like that and inside uh we're gonna add a spinner so for that let's go into our terminal I'm gonna shut down everything here I'm going to expand this a little bit and I'm going to write npm install react Dash Spinners like this and then I'm going to run my app again and I'm going to use bounce loader from react Spinners you can go ahead and do the documentation of the package and find any spinner you like the color is going to be hashtag 22c55e with the size of 40 like that great so now you can go ahead and maybe if you if you play around if you refresh enough times perhaps it's too fast so you won't be able to see it but uh we're gonna add loading to search and light as well so there will be at least one place we will be able to catch it uh all right so now let's go ahead and let's copy this loading an error let's copy and paste this to liked as well so copy loading and give it to liked and do the same thing to search so copy both the error and search and the loading as well great so go ahead and refresh this now and you can see how now when we go through our app it has a nice little loading effect for a second there great and if something goes wrong we would have had that nice uh error display great so that's what I wanted to do the only place we're gonna have to add that in the future is going to be the slash account which for now is a 404 page because we don't yet have stripe so let's go ahead and let's add a stripe now so let's go into our DOT environment dot local file here and let's prepare the environment Keys which we are going to need for strike so that's going to be next underscore public underscore stripe underscore publishable underscore key it's going to be stripe underscore secret key and it's going to be stripe underscore web hook underscore secret like this and after you wrote this please please please double check in my GitHub in uh dot environment.example that you didn't make a mistake here because a lot of people make mistakes uh with environment variables they uh have a typo in them and it causes a lot of problems but it's a very simple fix so always go into my GitHub and just confirm that you did not misspell it uh typos can be anywhere great and now what I want you to do and actually I want you I don't advise you that throughout this entire stripe integration process uh always have my repository open and compare whatever we'll be writing with what's in the repository so you can go ahead and take a quick look if something goes wrong and if it's a mistake there great so what I want you to do now is I want you to create a stripe account so I already have an account here don't worry this I'm going to create a new one here but basically find a way to create a new account a new business and you should be able to um you should be able to enter your account name so I'm going to go ahead and write a Spotify clone like this and I'm going to click create an account like this and after that there we go I have a completely blank screen here uh and where I created my new account and what I want to find next is I want to find the API keys and I don't know if you can see but here on the bottom of my screen in the bottom right corner I have a button API keys for developers I'm going to try and zoom in there we go you can see API keys for developers so when I click here I am redirected uh to this developers tab right here so you could have clicked here as well and then click API keys so basically create a new account on stripe go to the developers Tab and find the API keys and then first key you're gonna find is your publishable key so go ahead and copy that and paste it in this next public stripe publishable key like that the second one is the stripe secret key so go ahead and click reveal test key and copy that as well there we go one thing that you'll notice is make sure you have this test data thing visible in your stripe you can see how I have a little test data text here to ensure that you're working in test mode but even if you create a new account you cannot disable test node until you actually confirm your business uh in a in a depending on the country where you're from so don't worry but just make sure you're seeing uh this uh turned on and test data here and in your keys you're gonna have you're gonna see this test test like that great and for the stripe web hook secret we don't have that yet so before we do that what I'm gonna do actually is I'm gonna go ahead and now I'm gonna write a lot of code so again I advise you have my uh GitHub opened uh and we're gonna go ahead I'm gonna go create some helpers and some libraries for strike so go ahead and create a new folder in the root of your application called Libs like that and inside of lips the first package you're gonna install uh the first uh we're gonna create is called stripe.es like this so go ahead and import Stripe from stripe like that and write export const stripe sorry lowercase stripe is equal to new stripe like this process.environment that stripe underscore secret underscore key like that so again make sure that in your environment local you actually have the stripe underscore secret underscore key like that and the second argument is going to be uh our app so API version is going to be 2 sorry 2022 2022 11 15 exactly like that and add info inside I'm gonna give this name a Spotify Spotify clone video and a version is going to be 0.1.0 I don't know what is app info really does but just to make sure add something unique here so actually I'm pretty sure you can write whatever you want here okay and yeah to fix this uh just write question mark question mark and an empty string like this great so that uh does our stripe yellow here so now let's go ahead and let's create our stripe client evil so go ahead and create a new file inside lips called stripe client.ds like that and for that we're gonna have to install a new package so go into your terminal I'm going to go ahead and run npm install at stripe stripe Dash JS like this wait a couple of seconds and npm run that again so let's go ahead and import load stripe from at stripe stripe JS and also stripe type like this great and now right left stripe promise is equal to promise open curly uh pointy brackets stripe or null like this and expert constantly gets striped if there is no stripe promise then we assign the stripe promise to load stripe like this process dot environment that next underscore public underscore stripe underscore publishable underscore key like that question mark question mark empty string like this again make sure you have this in your environment local make sure there is not a typo between those two otherwise your code is not going to work all right and make sure you uh return stripe promise inside of this get stripe function like that perfect and now what I want to do is I want to create some helpers which we're gonna need in order to start creating web hooks so go ahead and create a new file inside the ellipse folder called helpers.ds like this so first import the price type from types because we're going to need that and now let's go ahead and let's create a YouTube that will fetch our URL depending on whether we are in production depending on whether we are on localhost depending on whether we deployed uh to versal or somewhere else so let's go ahead and write export cons get URL like this now we're gonna write let URL and first we're going to check for public site URL so process dot environment dot next underscore public underscore site underscore URL like that so this is going to be uh if we want to change our URL on Versa later so I'm just writing this video because it's helpful but don't worry you you will see the process of deployment later now we're going to write question mark question mark process.environment dot next underscore public underscore versal underscore URL so this is going to be deployed automatically uh by virtual if we so if we don't set this one you don't have to worry if we are on Virtual you're still gonna have this working uh and in the end we're gonna just fall back to HTTP slash slash localhost 3000 like this perfect so now we have the options for our URL here just make sure you didn't misspell this again you can what I advise you to do again is to take a look uh uh in my go into my lips and going to my helpers here and just double check that you have the same code uh if you're feeling confused great uh and now what I want to do is I want to write the code that is going to confirm that the URL we passed if we changed it for any reason uh includes HTTP s great so URL is equal to URL that includes http question mark URL otherwise go ahead and open template with rules like this and just write https slash URL like this great and let's also fix any trailing slashes so URL is equal URL dot share chair character act like that Euro the length minus one so we pick the last character of the URL which uh could be a trailing slash so if there is a trailing slash at the end in that case uh we're just gonna use that URL otherwise let's go ahead and assign that so template URL and we will add a slash manually great and in the end just return URL like this great now the second helper we're gonna get is post data so we're going to write our own little uh fetch Library here so we're going to use the fetch library with our modification here so go ahead and write export cons post data is equal to a synchronous it takes URL and data like that the type of URL is string the type of data it's an object which takes in the price and the price uh like this okay and now let's go ahead and open an arrow function like that so we have the price imported from Price types here great let's cancel log uh write uh post request URL data like this just so you know what's going on when you post now let's get our response so const response is equal to response a weight patch pass in the URL and in this object we're going to pass in the method which is going to be post headers are going to be new headers go ahead and add content Dash type which is going to be application slash Json like this and credentials are going to be same Dash origin like that and body is going to be json.stringify and pass in the data like this great so again if you don't want to write this helper since this is not that important you can just copy the helpers from my uh from my repository especially this post data or to date time so this is just some helpers that I found which we need for this stripe project great so after you have this response right here go ahead and write if there is if the response that okay is not clear in that case we're gonna console log there is an error in post like that and we're gonna showcase URL data and response like that so we can debug what's going wrong I'm going to throw new error response status text like that otherwise don't forget at the end just return response dot Json again I advise you to always take a look in my helpers because this is going to be very complicated and it will be uh foolish that you wrote the entire stripe correctly but make a mistake in here for example and then your project doesn't work so I highly advise that you take a look at the GitHub and just compare your code or just copy it if it's easier since this helpers are not that important and the last one we're gonna write is the to date time so expert cons to date time is going to take seconds which is a number like that and inside write a variable T which is new date and we're going to write the Unix Epoch start so 1970 0 1 0 1 p 0 0 30 0 0 Z like that and then we're gonna set T dot set seconds seconds return the like that alright so we finished our helpers again you can always double check them here if you want you can just copy the entire raw file and just paste it inside it's going to be much easier great and now that we have that we can go ahead and we can create the Super Bass admin uh file which is going to hold all of the helpers needed for the web hook of stripe so let's go ahead and do that so in ellipse create a new file called superbase admin dot DS like this so let's go ahead and let's import Stripe from stripe let's import create client from at Super Bass superbase Dash Js like this uh all right so let's just see if I made a mistake I did delete client like that all right then let's import database from types DB like this import price and product from types like that import the structure stripe wrong dot slash stripe and import to date time oops time from dot slash helpers uh and I'm just gonna check if this create client is up to date since if you remember with Super Bass we had some deprecated Imports so I'm just going to go and quickly Google whether this is still okay to not give you a deprecated version all right it's a good thing I checked we don't have this in our package Json so let's make sure we install that so let's go ahead and write uh npm install at Super Bass slash Super Bass Dash JS like this so we have that in our project and then npm run Dev again the great so now we have this so it looks like we already had it under maybe a oh this is not the version you should have my apologies so I'm gonna go ahead I'm gonna run this again uh oops I was looking at the wrong project let's see uh okay here it is super bass Super Bass J yes yeah my version is 2.23.0 that's the newest version on npm my apologies I was looking at stripe and I thought that was the version all right so make sure you have ADD Super Bass Super Bass JS in your project with a version similar to this uh basically if you can import create client uh it should be uh fine for you great so now that we have these helpers this Stripe Right here let's go ahead and create expert const um we're gonna write Super Bass admin is equal to create client and we're going to pass in the database like that and in here we're going to write process.environment dot next underscore public underscore Super Bass underscore URL like this and below that we're going to use process.environment.supabase underscore service underscore role underscore key like that and for both of those you can just use pipes to add an empty string like this and again every time you add environment variables go ahead in your environment local and check that you have uh both of those so next public supervised URL we have that great and super based service roll key Super Bass Service roll key right here you can feel free to copy from here and then paste here if you're not sure uh great now let's go ahead and let's create our first helper here called absurd product record so we're gonna enable our web hooks that when we add a new product on the stripe dashboard it's gonna get inserted into our database so I think that's really cool because it's going to save us a lot of time so const absurd product record is an asynchronous function which accepts the product which is stripe dot product like this so go ahead and open that so first we're gonna go ahead and write the product data which is a type of product which we have defined in our custom types like this so go ahead and open that and write ID is product dot ID active is product.active name is product.name description is going to be product.description question mark question mark undefined like that image is going to be product dot images question mark dot open array and pick the first one or null and metadata is going to be product dot metadata like that perfect so our types are matching great uh if you're having any errors here and you wrote it exactly as I wrote it that means that your product interface which is the one we wrote from here has something written incorrectly so you can always I repeat you can always go into my repository and double check your types great so now that we have the product data here we're gonna go ahead and we're gonna upsert that into Super Bass admin so const extract error from await super bassadmin Dot from products Dot upsert and go ahead and in upsert open an array and write product data like this great so I'm just gonna go and collapse this like that so it's a bit more visible great and then if there is an error in that case we're just going to throw new error so you're gonna just throw error like that great uh and then on the log open you can you can write something useful useful here so I'm going to write product inserted slash updated I'm gonna write product Dodge ID so in my terminal when I have my active web hooks I'm gonna see this information that I have added a new product in a nice way great now the second one is going to be a similar function which is going to add the price to our database so const absurd price record is going to be in a synchronous function which accepts the price which is a type of stripe dot price so go ahead and write const price data which is a type of price so this price is imported from our types like that go ahead oops go ahead and open that object here and just write ID price dot ID product underscore ID is type of price that product is equal to string in that case we're going to use price that product otherwise an empty string like that active is going to be priced up active currency we're going to use price that currency uh description price dot nickname question mark question mark undefined like that type it's gonna be uh price DOT type unit underscore amount is going to be price that unit amount like this uh question mark question mark undefined like that so we Define the type already uh all right so after you need to mount we have the interval which is price that recurring question mark dot interval like that great uh interval count is going to be price start recurring again question mark oops just don't forget to put this like that uh so price dot recurring interval count like this trial period days is going to be priced that recurring again question mark got trial period days and metadata is going to be priced at metadata like that so then we're gonna go ahead and write const error is equal to await super based admin from we're gonna write in prices like that and we're going to upset open an array and write a price data like this perfect if there is an error we're going to throw the error like that otherwise we're gonna write console.log and something useful so I'm going to write price inserted slash updated uh price dot ID like this so I can clearly uh debug what's going on great after that we're gonna write a function that is going to create or retrieve a customer so once create or retrieve a customer like that it's going to be a synchronous and let's go ahead and write email and user ID like that and let's go ahead and give it some types so email is a typo string whoops and user ID is a type of string as well great go ahead and open an arrow function here and first let's extract the data and error from await Super Bass admin from customers select try underscore customer underscore ID like this which is equal ID the user ID like that and single like this great so we work in the tables in the customers table we're gonna find the stripe customer ID using this user ID and we're looking for a single record great so if there is an error or if there is no data question mark dot stripe underscore customer ID in that case I'm gonna go ahead and create one so customer data go ahead and open an object here to give it a type of metadata go ahead and open an object again and write Super Bass uu ID like this which is a type of string and email which is an optional string like that and then go ahead and open an object here and let's go ahead and write metadata like that super bass uid is uuid like that perfect so now that we have that let's go ahead and write if there is an email in that case go ahead and write customer data that email to be email like this all right and after that let's go ahead and write const customer is equal to a weight stripe dot customers dot create customer data like that great now below that we're gonna go ahead and extract the error from a Super Bass so const error remap it to Super Bass error like this is equal to await super based admin from customers like this and Dot insert we're gonna go ahead and insert an array open an object inside give it an ID of user ID give it a stripe underscore customer ID of customer dot ID which we just created here using stripe great and now that we have that let's go ahead and quickly check if there was a super bass error if there was we are going to throw this super base error like that if it wasn't we're going to write console log and something useful inside so I'm going to write new customer created and inserted for and I'm gonna write the user ID like that and we're going to return customer dot ID and outside of this big uh if Clause so this only this this is only happening if there is no active customer but if we do manage to load the customer so if uh the person uh was on a plan on any plan uh in the past in that case we're just gonna write return data dot stripe customer ID like that perfect so below that we're going to use we're going to create another function uh copy billing details to customers so let's go ahead and write that so const copy billing details to customer using asynchronous function which accepts the user ID which is a type of string and payment underscore method which is stripe dot payment method like that great so let's go ahead and open this let's go ahead and write the customer variables or const customer is equal to payment underscore method Dot customer as string so make sure you put as string here great now let's go ahead and let's extract the name bone address uh from payment underscore method.billing details like that uh if there is no name or if there is no phone or if there is no address in that case you can just return like this great now let's go ahead and write a wait stripe.customers.update pass in the customer for the first one and the second one give it a name name phone and address like this and you can just fix this typescript error for now with a comment PS Dash ignore because some types are not compatible with what we've written and what stripe has updated so I found I I found this uh helpers inside some open source repositories so that's how I know that we can put this and it's still going to work for us uh great so now let's go ahead and write const error is equal to a weight Super Bass admin so it will not work in the users table here and we're going to update like this billing underscore address like that and we're going to spread the address inside payment method go ahead and spread the payment underscore method payment underscore method DOT type like that uh write Subs my apologies so dot equal here ID is equal to user ID like that and then I'm just going to write if there was an error just throw the error like that perfect again if you're having any trouble with this if you're getting any errors if something seems wrong on your part you can always go ahead and go into my lips here and go into Super Bass admin and just check everything is going on here great after we've written this copy billing details to customer let's go ahead and let's create a another function manage subscription status change so const manage subscription status change like that it's an asynchronous function it accepts the uh subscription ID which is a type of string customer ID which is a type of string and create action which is a Boolean by default it's going to be false uh great all right and let's just not put uh like that okay uh first let's go ahead and let's get some customer data so const data remap it to customer beta error no customer error like that it's going to be equal to await Super Bass admin from customers select we're only wanting the ID from where the stripe underscore customer underscore ID is equal to customer ID which we passed in uh yeah so just make sure you don't misspell it so customer ID like this and that single like that right and if we get a null customer error in that we just throw no customer error like that great otherwise we can go ahead and extract the ID so const ID remap it the user ID like this is equal to customer data and just put an exclamation point at the end to fix any uh type errors so you can just do that great now let's go ahead and let's retrieve a subscription from stripe so cons subscription is equal a weight stripe dot subscriptions that retrieve like this pass in the subscription subscription ID like that and in the second one open an object and write expand default underscore payment underscore method like this great so now that we have that description we're gonna go ahead and we're gonna create a subscription data which we are going to use to update so let's go ahead and write const subscription data it's a type of database public tables subscriptions sorry lowercase subscriptions like this and insert like that great so now I can go ahead and open this a large object so I'm going to expand this you can see the whole type so public tables subscriptions insert you should not get an error in this type so you can hover and you should get the definition of every one of them and make sure that subscriptions is lowercase great so let's go ahead and write ID which is subscription uh sorry subscription dot ID which we just fetched from here all right uh user underscore ID is uuid which we just created here great metadata here is subscription dot metadata like that go ahead and write TS Dash ignore for the next line so in here status is going to be subscription dot status like this uh price underscore ID is going to be subscription dot items um dot data first one in array.price.id like that uh now let's go ahead and write another es Dash ignore uh what we're gonna do here is quantity which is going to be subscription dot quantity all right so we have the quantity here cancel at is going to be uh sorry let's first do cancel add period and and let's give it a subscription dot cancel at period oops cancel at period end like this and then let's do the cancel at which is subscription dot cancel underscore ad like that uh great so let's go ahead and let's see I have an error here so I'm going to quickly go ahead and see uh what went wrong here well yes uh so we have to turn this into a date so basically first we're gonna check whether we have the subscription dot cancel at and then we're going to add a question mark here and we're going to use our helper to date time which we imported and we're gonna pass in uh this very same subscription dot cancel at like that and just write two ISO string like this otherwise null like that so we're going to use this a couple of times great so go ahead and below that uh write canceled uh cancel the ad so different one that's gonna be the very same thing so you can just go ahead and copy this entire line here and paste it so instead of cancel at it's going to be canceled at and we're going to pass in the canceled ad like this so make sure it's the same as the line above great you can go ahead and copy this again and this one is going to be current underscore Period start and the same thing so subscription and replace the cancel that with current Period start in the question mark and uh in here like that except this one uh is not gonna have yeah my apologies so this one is not going to be a template uh it's not going to be a question mark like this it's just going to be a direct uh modification to date time so even simpler great now below that we're gonna do the same thing with the current period and let's go ahead and write current period end like that and just add the current period end here great after the credit period end uh do the same thing with created like that so to date time is going to be subscription dot created to ISO string like this great and after that uh we just have a couple of more here so we have ended underscore at which is going to be again uh first we're going to check whether it exists so subscription dot ended underscore add question mark in that case we're going to add to date time to be subscription dot ended underscore at to ISO string like that uh otherwise null like this great uh and you can go ahead and copy that two more times for the second one we're gonna use the trial underscore start like that so just go ahead and replace ended at with trial start uh like this and don't forget to put a comma at the one above and the one here great and instead of the ended at for this one is going to be trial underscore and great so we're gonna replace this as well so do we need all of this here well no for our case we don't have any trials and stuff like that but I'm giving you here the helpers and web hooks for a much larger application so if you want to play around and add trials into your stripe this is going to work for you so that's why I'm doing this very complicated striped web hooks here because it's gonna save you a lot of time if you want to customize the application great and after you have the subscription data we're gonna go ahead and we're gonna insert that into the database so cons to go ahead and extract the error from await Super Bass admin from subscriptions like this absurd go ahead and open an array and write subscription data like that great if there is an error we can throw the error like that otherwise we're gonna cancel log and I'm gonna write something useful here so I'm going to write inserted slash updated subscription and I'm just gonna go ahead and write subscription dot ID for user uh user ID like that perfect and now just at the bottom of this uh I'm gonna go ahead and I'm gonna create an if Clause so if create action and end subscription dot default payment method and user ID in that case we're gonna go ahead and call away copy billing details to customer user ID and subscription dot default payment method as stripe dot payment method like this great so this is going to be our last resort if we want to copy billing details to customer this is a very expensive function but I saw it in this project in this Super Bass example so I assume it's useful for specific cases and perhaps if you're doing something more complicated with a super bass and stripe is going to be useful for you great and again I highly highly highly recommend that you open my GitHub and that you go through this through this code and maybe just check them one function by one function whether everything is okay you can go ahead and try and like copy and paste one and like paste it and just check if uh things have changed like paste it like this for example uh okay so I choose the wrong one so something like this right you want to go ahead and select maybe product data like this and paste it like this and see if there was any changes so in my case uh it's normal great uh and now let's go ahead and let's uh export all of those to export absurd uh product record absurd price record create or retrieve a customer like this and manage subscriptions status change wait okay so I noticed something so it's called create or retrieve customer not create or retrieve a customer so just remove the a here and let's find this where we do that so create or retrieve customer like that without a so yeah I mean this is just naming it doesn't matter much but you can see how easily a mistake can be found here uh great so now that we have this ready we can go ahead and we can create our web hook so we're going to do that using the new API folder so go and close everything here go into the app folder create a new file called API like this and inside of that you're gonna go go uh gonna go ahead then create a new folder called Web hooks like that and inside you're gonna write route.ds like that great so let's go ahead and let's create this web hook so first import Stripe from stripe like this uh you're gonna import next response from next slash server like this going to import headers from next slash headers like that we're going to import Stripe from add slash lib slash stripe like that and you're going to import uh from s slash slip slash Super Bass admin like this you're going to import absurd uh product record absurd price record and manage subscription status change great now we're gonna write the relevant events that we want to handle uh in our web hooks so let's go ahead and write const relevant events is equal to new set like this product dot created product dot updated price that created price that updated checkout.session dot completed customer dot subscription created customer dot subscription dot updated customer.subscription dot deleted like this so this is very very important because uh if you if you misspell this um you get your database and your stripe is going to be out of sync so please make sure that you go into my GitHub into webhooks route and just go ahead and try and copy and paste it to see if it's the same as your code so you don't have any mistakes here uh great so now that you have that uh what we're gonna build next is our actual uh post request so let's go ahead and Export asynchronous function post like this uh with a request which is a type of request like that and let's go ahead and get our body so Khan's body is equal await request dot text so we have to get it in a text format uh because we're going to pass that uh in a stripe webhooks construct event function which accepts a specific type uh of uh a string right so now let's get the signature so const Sig is equal to headers executed dot get and write stripe Dash signature like this great now let's add our web Hood secret here so constep hook secret like that uh so it's going to be process.environment dot stripe underscore that hook underscore Secret like this so I'm just going to go ahead and confirm in my DOT environment.local yes stripe webhook secret like this so make sure you have that here great so you can just move it like this right below that thing I had let events to be stripe dot event like that now let's go ahead and open a small try and catch block here since I try if there is no signature or if there is no web hook Secret in that case we will break the function otherwise we're going to create an event so event is equal to stripe dot web hooks oops web hooks that construct event and passing the body signature and webhook secret like that a great in catch let's go ahead and catch this error so there is an error a type of any we're going to console log error message and I'm just going to paste in error Dot message like that great and return new next response and in here we're gonna pass in web hook error like that error message and the status is going to be 400 so the say this is a very important uh for webhook for striped web hooks because it has a very visual um way of displaying what's going on with your web hook so there was when I was developing I forgot to put statuses and it was very unclear what was going on with my web hooks I thought they were not working but there actually were and vice versa and make sure you return the new next response I also forgot to do that while I was developing uh great so now outside of this try and catch blog we're gonna go ahead and check if relevant events has the current event DOT type so if the event that our web hook has caught is in the list of the events we want to look for in that case let's go ahead and do a specific task depending on what event is called so we're gonna use uh try and catch inside of that so first let's go ahead and write switch inside and I'm going to switch on uh event DOT type like this so let's go ahead and write case product.created or case product.updated so for both cases we're gonna have the same thing happen and that is going to be a weight absurd product record event.data.object as stripe dot product like this and remember to break whoops like that great now let's go ahead and do case price dot created or case price dot updated like this so inside of here what we're gonna do is we're gonna call await absurd price record like this with event.data that object has a stripe dot price like that great and don't forget to break like this great and now we're gonna do the subscription change so case customer.subscription dot created and you can copy this three times the second one is going to be updated and the last one is going to be deleted like this in that case we're going to call await uh sorry first we're gonna go const subscription is event.data.object as stripe that subscription like that and then we're gonna pass in a weight manage subscription status change we're gonna pass in subscription dot ID we're gonna pass in subscription Dot customer as string like this and event.type is uh customer dot subscription dot created so this is going to trigger our uh create action Boolean right here which we use here in the end to copy billing details to the customer great so now that we have this await let's also not forget to rate that as well and one more time I'm just gonna remind you please have this open and just confirm with the working code here because you can see how easy a mistake can uh I can hide in here so just always confirm with the actual GitHub great and after this one we're gonna have case of uh checkout.session dot completed like this and inside let's go ahead and create our checkout session so cons checkout session is equal to event.data dot object as stripe.checkout.session like that uh if checkout session that mode is equal to subscription in that case uh we're gonna go and get the subscription ID to be check out session dot subscription like that and again await uh manage subscription status change we're gonna pass in subscription I ID as string like that and we're gonna pass in uh checkout session that customer as string as well and we're gonna pass in through as uh the last argument so let's just see oh I made a mistake here so like that great and after date uh just use break as well uh let me just confirm yep so not inside the if my apologies so this is inside the if and outside the if Clause write a break like this and right default throw new error unhandled unhandled relevant event like that great and now uh in your catch uh just go ahead and write catch error here and write console log error and return new next response uh webhook error uh like this and you can just give it a status of 400 like that and at the end of our code this is very important uh just put return nextresponse.json received true and a status of 200 like that perfect so now we have a uh completely finished uh API web hook for Stripes so this was the hardest part of the project I know it's very complicated but payments are complicated in the future I'll try to maybe find uh only the relevant events for our product but this was the only functioning example that I found online so I kind of modified it for our Spotify here and I think it works very well actually so what we have to do now is we have to connect our stripe with our web hook here so in order to do that we're gonna have to go ahead and fill our DOT environment.localstripe webhook secret but here's the thing the thing about web hooks is let's go ahead and let's search for okay it's here web hooks so this is the thing you can if you want to test them in a local environment you need to download the CLI so you have to do this so what I need you to do now is I need you to find the web hook so you can just search web hooks if you cannot find them and click developer web hooks here and then you have to click on test in a local environment and that is going to guide you to download the CLI and log in with the stripe account so you can hear find ways to download and install the stripe CLI so if you're on Windows you can install have an installer if you're on Mac I highly suggest using Brew if you're a Mac I think is the simplest thing to do but you can see you have all the steps where you can download the files and extract them same thing for Windows if you want to you can even use Docker same thing for Linux basically you need to have the stripe CLI and after that is done and you'll be able to run this and then you'll be able uh to trigger an event to see if our web Hook is working or not so I'm just gonna go ahead and create a different setup here for you so you can see better just a second all right so to make this easier I just shut down my entire application so nothing is running on localhost you can see uh it cannot start so I have two terminals here and I am inside of my project you can do this inside Visual Studio code if you want to if you but you have to have two terminals open so in the first one I'm gonna run npm run Dev which is going to start my application again so let's just wait a second okay there we go and now what I want to do in the second one I want to run this stripe listen dash dash forward too so let's go ahead and I'm just going to collapse this a little bit so this one is a bit more visible great so I'm gonna write stripe listen dash dash forward Dash 2 and we're not gonna write this localhost 4242 because we are on a completely different one so we're gonna write localhost 3000 slash API slash web hooks and press enter and now you're gonna get your stripe uh a swiping web hook key so after you've written this make sure that you copy this stripe web hook key right here go back into your project and assign it to the stripe webhook secret and check throughout your project that you're using the proper uh environment variable here great and now I can go ahead and click this stripe trigger payment intent succeed for example and I'm just going to open a third tab here I'm gonna go back into my repository and I'm going to try and paste this and there we go my web Hook is working so I'm getting 200 positive events here so you can go ahead and just test this great and what we're gonna do next so throughout your entire developer development with stripe you're gonna need to have this running so I cannot stress this enough you need to have your web hooks running while developing otherwise your uh your database and your stripe is gonna get out of sync so what we're gonna do next is we're gonna go ahead and create a product so I'm gonna go into my Stripe Right Here and I'm gonna go into my product and in here I'm actually going to go into Super Bass uh right here just to see if this is uh the project that I'm working with he has a Spotify clone right here so currently I have no products and no prices in my database you can see it yourself go to Super Bass and go into prices and you won't have any products or any prices here but if our web hooks are working and if we create a product here so I'm gonna name this Spotify Premium for example and I'm going to give it a price you can choose for example US Dollars I'm going to choose nine dollars recurring and monthly like this and I'm going to click save product like this uh great okay so actually uh let's see I think I forgot to put a web hook somewhere so let me just see uh if I made a mistake so yes my apologies I completely forgot about a step so yes we have created this product right now but we're not gonna need it so you can go ahead and click on products if you haven't created it great so just delete the product because you're not gonna need it my apologies I completely forgot that we have another step in the web hooks so go ahead and go into your web hooks right here click test in a local environment and since this is already working for you and you have this running and you have this key right here click on done here uh all right and now let's go into our events here to see so products it's working alright so my apologies uh when I created a new account here I forgot that I have to run these steps so I did not run stripe login and that's why I didn't get the completed sign here and I didn't get this completed here so this is what I did I run stripe login so I'm gonna run it again here uh inside of my uh repositories I'm gonna copy this I'm gonna write stripe login and you can see how that gives me this link to open in a browser and once I click here you can see that I have this text and it's the same one from the terminal so I can allow access to my stripe there we go and now uh that is done and I'm gonna get this completed tag here and then I'm gonna go ahead so you probably already have your project running but I don't so that's why I'm running npm run Dev again here and then I'm gonna go ahead and call this stripe listen forward to localhost 3000 slash API slash web hooks again and after if you've done this again so every time you log in you're gonna get a new uh signing secret so make sure you copy it and you replace it here like that great so now that that is done I'm gonna go ahead and copy this again in a new tab like this I'm gonna run this and there we go all right so if I try I get it 200 so everything works correctly uh great now let's go ahead and click done here and you can see how I have completed here as well so now after you get this last completed that means that your web Hook is successfully configured and that your route here is working great so go ahead and click done here and now let's go into products here make sure you have no products available make sure you have no products in your database here so I'm just gonna wait for this to refresh I'm going to click add a product Spotify Premium and I'm going to give you the price of dollars so nine dollars for example recurring and I'm gonna click uh save product like this and there we go you can see how my web hooks are working here and I'm gonna go here and let's see there we go it's in our database and you can see the name Spotify Premium that's exactly uh what we wanted and we can also look at the prices there we go price which is linked to the product that we have which is active you can see that it's a unit amount is 900 which is actually 9.00 so nine dollars you can see the price type is recurring and the interval is month uh exactly what we wanted perfect so this is officially working your web hooks are working and all that's left to do now is to create uh the model which is going to show up and subscribe the user and the authenticate and the account page so I'm gonna repeat this while you are developing on stripe you need to have your web hook active I cannot stress that enough if you don't do that in that case your stripe and your database is going to be out of synchronization in production that is not a problem because we're not gonna have this running in a terminal but we're just gonna pass in the URL of our website um in the web hooks great so usually have one product here you should got this 200 on the product and you should have the price and the product in the database great so now uh we're gonna go ahead and we're gonna create uh the actual model to create this great great so I just want to make sure that you have both your project and your stripe web hook running in your terminal so I'm gonna move back to my code but in the background I'm gonna have this running and I'm gonna have my web hooks running so make sure you do the same all right so now let's go ahead uh and let's create a route that is going to create uh our checkout session so let's go ahead and let's go into our API folder one more time and we're going to create a new folder in here and it's going to be called uh create Dash checkout Dash session like this and inside create a new file route.ts again great so first things first I'm going to import from at Super Bass out helpers next JS whatever is the newest one so let's see create route Handler client like that that's what we want so create a route Handler client from add super base out helpers uh next JS perfect after that we're gonna need uh headers and cookies so headers and cookies from next slash headers like that after that you're gonna need next response from next slash a server like that we're gonna need Stripe from add slash add slash Libs slash stripe and we're going to need get URL from Libs helpers like that and you're going to need create or retrieve customer from Libs Super Bass admin so go ahead and write export as synchronous function post like this which takes the request which is a type of request and let's get the body of our product which we're gonna subscribe to so price quantity default that to 1 and metadata and before that to an empty object from a weight request.json like that perfect and now let's go ahead and open a try and catch block inside of here write const Super Bass is equal to create a route Handler client like that and let's pass in cookies and let's see if we can pass in the headers so no only cook is all right great and now what you want to do below that is extract the data user sorry data open an object whoops my apologies so just destructure the user like that uh from await Super Bass that's out that gets a user like this uh so just make sure you don't have a typo here like I do so Super Bass great and now you can have your user here perfect below that go ahead and write const customer is equal to await create or retrieve customer and pass in user ID which is user question mark.id or an empty string like that and email which is user question mark email or an empty string like that perfect so now that we have that let's go ahead and let's create a session so concession is equal await stripe dot checkout.sessions dot create like this go ahead and write payment underscore method underscore types to be card like that billing address collection is going to be required like this customer line underscore items like that open an array here so we're gonna give it a price which is price dot ID and quantity like that uh great below this array of line items we're gonna give it a mode of subscription like that allow promotion codes true subscription data is going to be a trial from plan true and metadata here great and let's pass in the success URL which is going to be our get URL slash account and our cancel URL is going to be just the get URL like this great so we have that now uh and then you can write return nextresponse.json ID session dot ID like that perfect and now that we have that let's catch the error here which is a type of any and let's console log the error and let's return new next response internal error and give it a status of 500 like that perfect and now while we are walking on the back end let's also wrap up our uh create portal link so let's go ahead and create a new API folder here create Dash portal Dash link like this let's go ahead and write a route.ts inside of that and again I'm going to import uh from at Super Bass slash out Dash helpers next JS I'm gonna import uh create a route Handler client like that I'm going to import cookies from next slash headers like this I'm going to import next response from next slash server like that I'm going to import Stripe from Libs stripe like this I'm going to import get URL from Lil's helpers like that and I'm going to import uh create or retrieve customer from leads super based admin so let's go ahead and write export asynchronous function host like this it's not going to accept anything and just try and catch and first let's get our Super Bass so create um route Handler client like that and pass in uh the cookies like this great and now let's extract data and let's extract user from it from Super Bass uh sorry from I'll wait Super Bass dot alph dot get user like that perfect if there is no user throw new new error code not get user like that perfect otherwise const customer is equal to a weight create or retrieve customer like that user ID user.id or an empty string email user dot email or an empty string as well like that perfect if there is no customer let's also throw an error for that so if there is no customer throw new error no customer sorry let's say could not get customer like that uh all right now let's get the URL so const URL is equal to a weight stripe dot billing portal that sessions dot create using our customer and let's give it the return URL of get URL execute that slash account great so now we are able to create our subscription link and our uh portal link where users can remove their subscription in if they want to and they will be tied to their account when they click on it's a return next response Json URL like that perfect let's go ahead and write the cache here and let's just write console log error like that and uh return new next response internal error and just give it a status of 500 like this uh perfect great so now that we have that let's go ahead and let's create uh our subscription model so I'm going to go ahead and I'm gonna go into my hooks folder and I'm going to create a new file use subscribe model.ds so let's go ahead and we can actually copy everything from use alph model so just find the out model and paste everything in your subscribe model and just replace the alph model instances with subscribe model like this everything else is exactly the same perfect and now we can go ahead and go into components and create a new file a subscribe model.bsx like that let's go ahead and let's mark this as use client like that and let's give it a name of subscribe model like this and inside all I'm going to return for now is our model component from dot slash model like this and I'm gonna give it the children of uh subscription like this I'm gonna give it a title of only for premium users I'm gonna give it a description of listen to music with Spotify Spotify premium like that I'm gonna hard code is open and on change it's just going to be an empty Arrow function like this and now I'm going to add this subscribe model uh into our model provider so I'm going to go into model provider and I'm gonna add in subscribe model like this and you can import that from add components subscribe model and I'm going to refresh this and I should have the model open there we go so only for premium users listen to music with Spotify Premium so let's go ahead and let's actually dynamically create this content here so I'm going to write let content like this and by default it's going to be an empty div which is which will say no products available like this and I'm going to give the class name of text Dash Center so that's going to be our content by default like this great uh and then what I'm going to do is I'm gonna go ahead and I'm actually going to find a way to load our products so the way I want to do that I want to go back into my layout so go ahead and find a layout uh just a second so app folder layout right here you're gonna write const products is equal await get active products with prices uh now this does not exist yet so obviously uh we have to create that so let's go ahead and let's go into actions and create a new file get active products with prices dot DS so get active products with prices dot es the same text that I've written here get active products with prices all right and uh what we're gonna do inside of that is first we're going to create well actually it's going to be very simple to our get songs for example so let's copy get songs inside and replace it just rename the action to get active products with prices like this and instead of returning a song it's going to return a new type called Product with price so let's go ahead and add product with the price here and now let's go into our types and let's just export interface product with price extends product and just write prices question mark price like this and I advise that you put those uh below uh product and price like this so you have both of those defined before it great so product with price extends the existing product and adds in the prices with a price array like that perfect and now we can go back here and you can now safely import this from types and we don't need this song like that and what it's going to call so it's going to go from products like that it's going to select everything it's also going to populate the prices so prices like this it's gonna call everything inside we're going to choose only the active one so active must be true uh we're also going to check if the price is active so prices that active also must be true like that we're going to order them by metadata index like this and we're going to order them by a unit underscore amount and we're going to use this foreign table to be prices like this perfect so that's going to fetch our product with prices and now we can go back into layout right here and fetch the product with prices here and I'm gonna pass that uh into our uh model provider here so go ahead and write products products like that let's go into model provider and in this model provider what we're gonna have to do is create the props so interface model provider props it's gonna accept products which is product with price from types like that let's go ahead and assign that so react.fc model provider props products like this and we're gonna pass them to subscribe models so products products like that let's go here let's go interface uh subscribe model props products products with price which is an array like this and just assign this so react.fc and then we get the products like that perfect so now that we have uh this product we can go back uh and start developing in this subscribe model so what I want to do now is I want to check if products that length in that case my content is going to be different so I'm going to open a div here and I'm going to map over the products so products.net I'm going to find the product like this and I'm going to open uh a function like this I'm going to check uh if there are any prices so if there are no product dot prices question mark dot length in that case I'm gonna return a div I'm gonna give it a key of products.id and I'm going to write no prices available like this um otherwise I'm going to return a map over those prices so product Dot prices.map I'm going to get the individual price and I'm going to return a button which you can import from dot slash button like this I'm going to give it a key of price dot ID like this and I'm going to write in here subscribe for uh and now I'm gonna write a function to format the price so let's go ahead and let's just quickly do that here at the top so const format price it accepts the price from types like that const price string is going to be equal to new I and the l dot number format choose N Dash us open an object style is going to be currency like that currency is going to be price dot currency so whatever currency we chose from stripe minimum fraction digits is going to be zero dot format uh let's go ahead and open parenthesis here and write price question mark dot unit underscore amount or zero slash 100 sorry divided by 100 okay let's see uh what's going on here so so I made a mistake it's currency like this okay so make sure you don't misspell currency and just return price string like that and now you can use this format price and use format price inside uh for the price object like that uh and I'm just gonna write an interval as well so subscribe for the price or a sorry price dot interval like this and there we go you can see how I loaded the only product that I have if you were to add another product in your database that would appear here as well great so now that we have this let's go ahead and let let's give this uh button some other props here so besides the key let's go ahead and let's write on click so my apologies on click like this handle checkout price we're gonna create handle checkout later disabled it's going to be is loading or price.id is equal to price ID loading we're going to create both of those fields and class name is just going to be mb-4 so of course we will now get errors because we don't have is loading we didn't have price ID loading and we don't have the handle checkout so let's go ahead and let's first create our handle checkout here so I'm going to go here I'm going to write const handle checkout like that it's going to be an asynchronous function which accepts the price which is a type of price like that and let's first write uh yeah first we have to add some states here so let's go ahead and write const my apologies price ID loading set price ID loading like that is equal to use state which is a type of string so we're gonna set the currently loading ID in this state and let's import your state from reacts make sure you don't accidentally forget that great I'm just gonna reorder my inputs a bit perfect so now that we have a price ID is loading uh let's also fetch our user so const user is sorry cons the structured user is loading and subscription we're gonna need that from use user from ad hooks Slash use user like this so that's the hook that we created at the beginning great and now we have that is loading we have that user and we have the handle checkout grade so the errors should go away so make sure you have handle checkout is loading and price ID is loading great now let's go inside of this handle checkout and write set price ID loading to be price dot ID like that if there is no user uh set price ID loading goes back to false uh sorry it goes back to undefined because it's not a Boolean and return post which you can import from react hot toast like this dot error must be logged in so just another check here uh if there is a subscription so if the user has already been subscribed uh set price ID loading at the point and just return those uh which info informative we will say already subscribe uh just make sure you don't uh add a typo like I did great and now that we have that let's actually go ahead and create a checkout session so try I'm gonna open a try block and I'm gonna write const and I'm going to extract session ID from await post data which you can import from our helpers right here so we created post data so go ahead and write post await post data open an object and write URL is going to be slash API slash create Dash checkout Dash session so that's the API that we created recently checkout Dash session like that and we're gonna pass in the data with the price like that perfect and after we get the session ID I'm gonna write constripe to be await to get a stripe which you can import from Libs stripe client like this so go ahead and add that as well now that you have that I'm going to write stripe question mark dot redirect to checkout and I'm gonna pass in the session ID like that so that's going to create a custom checkout screen for the currently logged in user and if there is an error toast.error uh I'm gonna pass in error as error let's just wrap those that in the parentheses like that that message like this perfect and finally set price ID loading is going to be undefined like that perfect uh and one more thing I want to add is just below this if products.length I want to add a third case uh for our model and that's going to be if we are already subscribed so if subscription in that case content is going to be a div which says already subscribe like that and we're gonna give you the class name of tax Dash Center like this uh so let's go ahead and let's see if maybe we made some mistakes or if everything is fine so I'm gonna extract that you can see the how in my database I currently have no customers and I have no subscriptions so I only have one product and one price in my database and you should have the same but I have no subscriptions and no customers and same thing on my dashboard right so only have one product here and that's the product that I have in here and that's the price that I have in here as well so let's go ahead and try and see if this is working or if we did uh something incorrectly and there we go it works for me so it opened a checkout link here and now if you want to test this so make sure it's in test mode here I'm gonna write four two four two four two four two four two and everything else can be anything you want only this date needs to be in the future so you can just write literally anything you want this is just testing and just make sure you add four two four two four two because that will trigger a success and you can see how it's immediately linked to my account and I'm going to click subscribe and we're gonna see if that's gonna successfully add uh our uh customer right so we already redirected to slash account but that does not exist yet so that's completely fine but let's check in my customers now there we go I have a customer let's go into my subscriptions to see here all right so something went wrong with subscriptions it seems but let's see if the customers are here the customers are here uh all right so we're gonna have to do uh some checking to see why the subscription was not created all right so I think I found our culprit so I looked at the errors when we created the subscription and you can see that I have this subscription is not defined maybe you don't have that maybe it even worked for you uh so the reason it doesn't work for me at least is because I have this typo in subscription so I'm going to write subscription.quantity like this here so you can see okay let's try again so I need to write subscription like this and that yeah so the the TS ignore actually made it so that I didn't find that this did not exist but yes uh okay let's go ahead and let's try now I'm not sure if I can try uh again since I just kind of created something and kind of not created something so let's go ahead I'm gonna try and see uh if maybe this will create a subscription object I'm not sure I'm gonna click subscribe now all right and there we go that created the subscription perfect so it was a small type but you can see how that happens and there we go it says already subscribed here great so it was a very small error but that's why I told so many times please confirm with my GitHub because it's so so easy to create a mistake here great so what we have to do now is we have to enable uh this out model um on a bunch of uh screens that we want great so instead of having it hard coded and always opened I'm gonna go ahead I'm gonna go into my subscribe model here and what I'm going to do is I'm going to modify uh how it's controlled and how it's open so let's go ahead and write const subscribe model is equal to use subscribe model like that all right and now what I'm gonna do is I'm gonna write my own change function so constant change is going to be equal to open which is a type of Boolean like that if there is no open in that case subscribe model that on close like that and we're going to use this on change um inside uh of our own change here like that and default is open is going to be subscribe model dot is open like that so now by default uh this model should not be opened and now I want to find uh all the places where we use this model so that we can safely protect our front end from it so let's go ahead and let's go into and let's go into our library first so I'm going to go into Library like this and what I advise you to do is if you are successfully subscribed uh go ahead and log out and I'm going to create a new account here which is not um subscribed so I'm gonna go ahead and confirm my email here all right so I just want to be in a new user that is not subscribed to anything so I don't want to so just create a new user that you have not clicked subscribe with great and now that you have that you're gonna go into Library here and now we can use that subscribe model so con subscribe model use subscribe model like this which you can import from ad hooks use subscribe model and now here I wrote to do check for subscriptions and that's what we're gonna do so instead of just user I'm gonna also write subscription like that so if there is no subscription either in that case return subscribe model dot unopen like this so since I don't have subscription with this account when I click here you can see that it says it's only for premium users perfect so that's one place where we want this now let's go ahead and let's go into our use on play hooks right now I can go ahead and I can play my songs right but I only want to restrict that to users who have registered so let's go ahead and fix that here so inside of this um so inside of this uh on play in the use on play hook I'm also gonna check for a subscription so go ahead and extract subscription like that if there is no subscription in that case return subscribe model which we have to add so let's go ahead and do that so con subscribe model is equal to use subscribe model like that so cons subscribe return subscribe model dot on open like this perfect and now let's go ahead and try uh and play something all right so I had a quick error but I think it was just hot reloading nothing else yeah okay and now let's try and click and there we go so only subscribe the users can now uh play songs and add songs and let's see if I log out and if I go into uh my other account where I have subscribed there we go you can see here I can add this song and I can also Play the song Perfect so that's exactly what we wanted and that's pretty much it all we want now uh oh see that on reset it did not unlock out it did not remove this player so let's go ahead and quickly fix that let's go into header right here and let's see yes there we go to do reset any playing song so we wrote that perfect let's go ahead and add cons player is equal to use player like this and I what I want to do is just run player dot uh reset like this so now every time we click on logout uh it's also going to shut down any uh playing songs Perfect all that's left is to create the account screen so the user can remove their subscription great so let's go and let's create uh and let's create our app folder and create a new folder called account like that and inside create a page.psx and you can actually immediately uh copy the error and loading from it and paste it in the account as well great now let's go into this uh page.dsx and let's just find account the account page like that and go ahead and log in into your account and just go ahead and try and click on this user now and you should be redirected uh to slash account and you should be seeing a visible account page so let's go ahead and write a class name BG Dash neutral Dash 900 rounded LG h-w Dash full overflow Dash hidden and overflow Dash Y dash Auto like that and inside I'm gonna add a header component and I'm going to give this a class name of prom Dash BG Dash neutral 900 like that uh great because I wanted to have similar styles to search I'm going to create a div inside I'm going to give this a class name of nb-2 Plex Flex Dash call and GAP Dash Y dash is six and inside I'm going to create a heading with account settings like this last name backslash white backslash 3XL and thunder semi bold like this perfect so we have account settings inside and now here I'm going to write account content like this and inside the account folder create a new file folder called components and inside I'm going to write account content.tsx like that Mark this as use client like that and let's go ahead and let's create our uh account contents here so I'm just going to write div account content I'm gonna go back into page and I'm going to import that so it's quickly resolved there we go like that and inside of here let's go ahead and let's add the router subconscious router from next slash navigation like this if these errors keep appearing you can always shut down your application and start again great come subscribe model is going to be you subscribe model from hooks a use subscribe model like that we're also going to have the users of const is loading subscription and user from use user remember to import that from cooks use user and not the Super Bass one great let's add our loading and set loading here to be used State Pause by default just add in that perfect now use effect great now inside you write if we are not loading and if there is no user in that case we are going to router.replace to slash so we're going to restrict this so it's only available to authenticated users so ad is loading and user and router to this dependency array now let's create a function that will redirect the customer portal so cons redirect to customer portal is asynchronous like this is that loading it's true open a try block const URL error await host data from Libs helpers so I'm just gonna reorder this like that from Libs helpers like that go ahead and write the URL to be slash API slash create Dash portal link so that's a API route that we created recently so create Dash portal Dash link right here all right uh great and now let's just write window.location.assign URL like that catch the error and if there is an error in that case uh you can just write post from react hot toast so I'm gonna move that to the top as well on the right Toes that error here error Dot message like that [Music] all right let's write it like this so error as error Dot message there we go uh great uh yes that's all I want to do here and at the end I just want to set is set loading to pulse like this perfect and now that I have that uh let's go ahead and let's actually style this so let's give this a class name of mb-7 bx-6 like this great if there is no subscription and in that case let's open the div which says no active plan and give this a class name of Plex flex.cole and get get Dash O Y dash or like this and we're gonna put this inside a paragraph like this so paragraph there we go and a button from the components button like that subscribe and we're gonna give this an on click which is going to open uh sorry subscribe model that unopen without execution like that and let's give it the class name of w open square brackets 300 pixels like this so this is gonna show if we have no active plan and if we go into our account page great uh now besides that we're gonna add a special case if there is a subscription so if there is a subscription in that case we're gonna go ahead and open a different div let's give this a class name of Wax Black slash call Gap Dash y-4 and inside let's write the paragraph you are currently on the open uh B like this subscription Mark Dot uh prices question mark dot products question mark dot name plan dot like that there we go so you're currently on the Spotify Premium plan perfect and below that a button component uh which is gonna say open customer portal like that let's go ahead and give the class name of w Dash open square brackets 300 pixels like that disabled is going to be loading or is loading and on click we're gonna call redirect to customer portal like that and that should be it for our Spotify clone now if I click here I should get okay there we go so we have something wrong I'm gonna go ahead for a second and debug what happened alright so the error I got says the following and says you can't create a portal session in test mode until you save your customer portal settings in test mode so let's go ahead and I if you have the same error you should probably see it and you can go ahead and click here to see where that is going to open so I'm going to go ahead in here I'm gonna try and find what they meant by that so let's see uh settings billing portal let's see billing can I find a portal here I'm just going to resolve this offline so I'm going to tell you what the solution is all right so I think I found it go ahead and search for customer Oracle and you go to settings billing customer portal like this and click activate test link and there we go I think that should work now I'm gonna try again I'm gonna refresh here I'm going to click open customer portal and there we go we are in our test portal and I can cancel my plans you can see yeah since we played we had the I had that error with subscriptions so it looks like I have three subscriptions now so yes but this is all in test mode so that's completely fine uh we can remove everything from your database and everything from your stripe and start again and everything will work completely fine uh great great job all that's left is to De Pro deploy this application so that's what we're gonna do next all right so all that's left to do is to deploy this on Virtual but before we do that I just want to search to the project if we have everything left in to do and we do right here so I wrote that to do in media items so go into your media item component where you can find that in your Global components file right here and what I want you to write inside is instead of this to do we're going to go ahead and add the player so const player is going to be equal to use player like this and you can import that from add slash hooks use player like that and instead of this to do you're gonna go ahead and write player that set ID data.id like that and go ahead and return that like this um nothing much should change because I think everywhere where we use the media item so I'm just going to quickly go through them here so in liked content we add them on click insert content we add an on click in library we have an on click and in player content so in player content we don't have that on click grade so it's going to be used at least there uh great all right so if you want you can add that if you don't you can also just remove it because I don't think this is actually used anywhere except in our actual player so I'm going to go ahead and just test if this still works I'm gonna wait a couple of seconds and yes it still works great uh and now what we have to do is we have to go into GitHub right here so I'm going to expand this a little bit and what we have to do is we have to create a new repository so click new repository here and name this Spotify Dash clone something like that make it public or private and click create a repository like this great and we're going to use this second option so push an existing repository from the command line so I'm going to go ahead uh and I'm just going to find if I have any running terminals so just a second all right so go into your terminal right here you can shut down the app like that and first thing let's commit uh everything here so I'm going to go ahead and write git add and get commit final like that so make sure your stuff is committed here and then go ahead and just copy this entire thing so make sure everything you wrote in here has been committed so you should not have any active changes and then you can just paste everything here and press enter and then when you refresh you can see that I have the entire file right here great so now what we have to do is you have to go in our versal dashboard and click add new project right here and you can now import your Spotify clone repository which we just created so I'm going to click import here and make sure you click on the environment variables right here and in your code find dot environment.local like that great so go ahead and select all of that you can copy it and just paste all of that here and there you go you can see how everything is set up now and of course we're gonna have to change our stripe webhook secret but we are going to deploy with it first and then we're going to change it later so let's just go ahead and click deploy to see if we have any errors which we have to fix so I'm going to expand this and I'm gonna go and pause and I'm going to return after this has been deployed or if I caught any errors alright so I just unpaused the video uh so I can show you that I'm getting this warnings right here but so far that has not stopped the build process so if you're getting this as well don't worry it looks like they are not breaking and there you go it seems like everything else was successful so I think the only thing that can break it is actually typescript errors so you might have a typescript error if you have it it's going to be very clear in which file it is and you can you can find it in your project and fix it there but this the encoding is normal and there we go so now I have my site right here and let's just wait a couple of seconds so that my domain is assigned so I'm going to go ahead and click here and there we go I now have my domain here but one thing that won't work right now is stripe so let's go ahead and let's copy this URL that you now have which Verso has assigned to you and go back into Stripe Right here and find your web hooks again so go to developer web hooks like that and we already have a local listener so that's what with what we did with the stripe CLI but now click on ADD endpoint here like this okay so I just have to confirm my password so let's just wait a second for that all right and after I've done that uh you can see that now uh I have this add an endpoint selection here so I'm going to paste my endpoint here again you can find that uh in your website uh once you click on this icon in reversal so just copy that URL and paste it here and now go ahead and click on events on your account and click select events right here and click select all events so we want to listen to all of them and then click add events at the bottom like that go all the way uh to the bottom and click add endpoint like this and let's just wait for a second and now very important so you have to change your signing secret so don't use this ID but instead click on this signing secret right here and click on reveal like that and then you're gonna copy that and you're gonna go back on universal so go ahead and go into your dashboard right here so you can just find it uh let's uh let me try I'm going to click here so you should have it right here so click on it like that let's go ahead and let's find the settings for this all right so go ahead and here in these tabs right here go to settings and go to environment variables right here go ahead and find the stripe webhook secret open these dots and click edit and just change it to the new one like that and click save and after that you're gonna have to redeploy so go into your deployments right here find the last one Open click on this uh tabs right here and just click redeploy and do not check use existing build cache so make sure this is unchecked like on mine and click redeploy like that so I'm gonna go ahead and wait a couple of seconds and then I'm going to show you whether this works or not great so it deployed successfully uh and I'm gonna go ahead and visit my website here again and I want to go into my Super Bass here so I have two users here so first let's check uh if that works I'm gonna go ahead and try and create a new user so I'm going to use a new email right here uh okay let's just click on sign up instead sorry so sign up instead of login and the email has been sent so I'm gonna go ahead and confirm my email in a second all right so I successfully confirmed my email but one thing that happened is that the URL in my confirmation email led to localhost like this so I don't want to do that so for that you can go into your authentication right here and click on URL configurations and just go ahead and copy your URL and paste it here as well and save that and then that is going to create proper uh email templates based on your deployed applications so my bad I missed that but nevertheless I managed to confirm my user here so let's go ahead and let's try and play the song all right it says I need to subscribe so let's go ahead and try that now so here I have the stripe waiting for events so let's go ahead let me just find my uh where is my there we go it's here so I'm gonna go ahead and try and register again sorry I'm gonna go ahead and try and subscribe again let's see if that works right here let's wait and I'm gonna go ahead and try now uh okay I got logged out so let me just see if I go back inside foreign Play the song now alright so it's still not working let's see uh what went wrong all right so I figured out why it's not working I made a very dumb mistake so go back into your back hooks go ahead and find the web hooks right here and you can see that the URL I put is just my page when it should be slash API slash web hooks so go ahead and click here and click on update details and just add slash API slash web hooks like this and then click update endpoint like that so you can see that I played around I try to create some more products some more subscriptions but it did not work so I'm gonna go ahead now that I've changed it the slash API slash web hooks my apologies I'm gonna go ahead and try again so I'm gonna subscribe one more time and let's hope this one works so I'm gonna click subscribe here let's wait a second and there we go we have a second subscription here and let's see if that's gonna work here I'm just gonna go and uh log in again yeah sometimes try uh logs out your account but let's see there we go you are on Spotify Premium plan great great job and now I can actually click here and there we go my song is playing uh we'll play there we go now it's playing so great great job my apologies you in your web hook make sure you put slash API slash web hooks in the end otherwise you're gonna have the same uh error I did and that is that you will successfully get a new customer on stripe but for me it did not transfer into the database but now after I fix the webhook endpoint in stripe uh it's working uh great great job you did a very hard project thank you so much for watching uh remember to leave a like share and subscribe if you like the video and see you in the next one
Info
Channel: Code With Antonio
Views: 479,859
Rating: undefined out of 5
Keywords:
Id: 2aeMRB8LL4o
Channel Id: undefined
Length: 407min 59sec (24479 seconds)
Published: Mon May 29 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.