Full App Build - Dev to Deployment - Next.js, Prisma, Neon & Clerk
Chapters38
The video introduces building a full Next.js app with a Neon cloud Postgres database and Clerk for authentication, outlining the stack, features like server actions, and the plan to store users and transactions with Prisma migrations.
A practical, end-to-end build showing how to stack Next.js with Prisma, Neon, and Clerk to create a full CRUD expense app from dev to deployment.
Summary
Traversy Media’s walkthrough shows Brad building a complete Next.js 13+ app that uses Neon as a Postgres serverless database, Prisma for migrations, and Clerk for authentication. He kicks off by outlining the stack and sponsor tools, then scaffolds a Next.js app with TypeScript, wiring Neon as the data source and Prisma as the ORM. The tutorial covers server actions (no API routes), database migrations, and a clean separation of server/client logic. Brad demonstrates user sign-in with Clerk (including Google or email/password), then implements a check-user utility to sync Clerk users with Neon. The app evolves to include transactions, a balance view, income/expense breakdown, and a transaction history with delete capabilities, all persisted via Prisma. Finally, he shows deploying to Vercel (with a small npm script for Prisma generation during deploy) and tests sign-in, data persistence, and UI updates in production. It’s a hands-on, opinionated guide to marrying modern Next.js features with real cloud services for a production-like workflow.
Key Takeaways
- Neon provides a Postgres serverless database with branching, a generous free tier, and easy connection strings used by Prisma migrations.
- Clerk handles authentication with support for Google and email/password, with a generous free tier up to 10,000 monthly active users.
- Server actions in Next.js replace traditional API routes for database operations, enabling server-side Prisma calls directly from components.
- A small but essential check-user utility keeps Clerk-authenticated users synchronized with Neon by creating local user records on first login.
- Prisma migrations are generated and run to create user and transaction tables, then Prisma client is used from a shared lib/db.ts to avoid reinitializing on hot reload.
- The app includes real-time-like UX touches: server actions return results, revalidatePath refreshes after mutations, and React Toastify provides non-intrusive notifications.
- Deployment with Vercel is demonstrated, with a workaround script (po install) to ensure Prisma client is generated during build for Prisma usage in server actions.
Who Is This For?
Frontend and full-stack developers who want to build a production-like Next.js app with a modern backend stack (Neon, Prisma, Clerk) and learn server actions, migrations, and deployment patterns.
Notable Quotes
"Neon is a cloud database and postgres serverless platform that I've recently used in a few projects and it's extremely powerful, easy to use and affordable with a very generous free tier."
—Brad introduces Neon as the database backbone for the project.
"Clerk is an authentication and user management system that's incredibly easy to use and you can have your users authenticate with Google, GitHub, or just email and password."
—Brad explains Clerk's capabilities and options.
"Server actions... there's no API routes we can just create a function in an actions file and do all of our Prisma database stuff from there."
—Key concept demonstration for Next.js server actions.
"We want to save that user in the database... a check-user utility will see if the Clerk user already exists and will add it if not."
—Shows how Clerk users are synced with Neon.
"If I click sign in with Google, Brad demonstrates that the sign-in flow works and the user data appears in Neon."
—Illustrates end-to-end authentication flow and persistence.
Questions This Video Answers
- How do server actions in Next.js replace API routes for database interactions?
- What is Prisma Migrate Dev and how do you set up migrations with Neon?
- How can I sync Clerk users with a Neon database in a Next.js app?
- What are best practices for deploying a Prisma-powered Next.js app to Vercel?
- How do you implement a balance, income, and expense view with server actions in Next.js?
Next.js 13+ Server ActionsPrisma ORMNeon DatabasePostgreSQL serverlessClerk AuthenticationTypeScriptServerless DeploymentVercel deploymentData migrationsServer/client code separation
Full Transcript
hey what's going on guys so today we're going to build a full nextjs react application with a database and authentication and I reached out to two of my favorite products to see if they wanted to collaborate on this project so this video is sponsored by Neon and Clark neon is a cloud database and postgres serverless platform that I've recently used in a few projects and it's extremely powerful easy to use and affordable with a very generous free tier and it offers branching and some other cool features that I'll talk about later and then clerk is an authentication and user management system that's incredibly easy to use and you can have your users authenticate with just about any service including Google Facebook GitHub as well as just email and password and clerk also has a very generous free tier with up to 10,000 users monthly so there's no paying for anything or adding credit card info to to follow along with this project now as far as what we'll be building some of you may be familiar with the expense tracker application from my 20 Vanella projects course we also redid it with react and VJs now we're going to take that app and enhance it to use neon as our database to store users and transactions we'll also be using Prisma for migrations and interacting with the database and then we'll use uh we'll add full authentication and access control with clerk so users can log in with email and password as well as their Google account and all users will be saved in the neon database and will only be able to access their own transactions all right so we're also going to be using react's new server actions so there's no API routes we can just create a function in an actions file and do all of our Prisma dat database stuff from there so it's a relatively in-depth project for YouTube and I think you're going to learn a lot and you'll be able to start building your own stuff with this stack and I'll have the final repo in the description along with links to Clerk and neon so check them out and let's get started all right guys so just a couple things I want to I want to go over a couple websites and I'll have the links to all these in the description so of course we have nextjs dorg that's where you can find all the documentation for next we'll be using things like server actions so you might want to just use that as kind of a supplement and then I have the final repo here expense tracker nextjs so this link will also be in the description and if you need any code Snippets uh we're going to grab the CSS from here we're just using a global CSS file so we don't really have to worry about styling and stuff um but yeah so that's the repo and then clerk.com is what we're going to be using for authentication and user management so you will need to create an account it's there's a very generous free tier as you can see you get up to 10,000 monthly active users so very generous free tier you don't have to add credit card or anything like that and uh you'll have your dashboard with all your users so we'll be using that along with neon for our database which is a postgres serverless platform very easy to to get set up so pretty early on in the course we're going to set up our database and connect to it and then Prisma is the OM we'll be using for migrations for uh just interacting making queries and stuff like that so let's go ahead and just go into our terminal and just navigate to where wherever you want to create this we're going to run npx create next app at latest and then I'm going to call it expense D tracker Das nextjs and I'm going to say yes to typescript if you don't want to use it that's okay too I'm going to say no to es lint no to Tailwind because we're just using a global stylesheet Source directory no app router yes and then customize the Alias no all right so now it's just going to set up all of our dependencies and now what I'm going to do is just CD into that directory and then just open up vs code of course if you want to use a different editor you can all right so from now on I'm going to use my integrated terminal so I'll just close this one up and I'm just going to run the dev server so it's say npm uh run Dev so that'll open on three 3,000 let's open that up takes a second the first time you load it and there we go so now we have our just basic landing page so let's just do a little bit of cleanup so in the app folder I'm going to get rid of the page module CSS we don't need that and in the page.
TSX which is the homepage I'm going to just delete everything and just create a brand new component now I'm using uh a specific extension called simp react Snippets and with this we can just do sfc I believe is what I what I use yeah stateless function component and it's an arrow function so let's do sfc enter and then we can give it a name let's this is the homepage so that's what I'll call it then we can tab into the props we have no props for this so we'll tab again into the return and let's put a main tag and in that I'll just have an H1 and we'll say expense tracker and there we go all right so the global CSS I want to change this so I'm going to grab the the global CSS from the repository the Link's in the description just go into the app folder and then Global CSS and let's just grab that and replace this with what we just copied save that and there we go all right so the next next thing I want to do is open up the layout.
TSX and couple things I want to use the robotto font so I'm going to bring that in I'm going to select these three instances of enter with Commander control D so twice and then just change it to robotto now see how it preserved the case this this stayed uppercase this was lowercase this is uppercase R that's because of an extension that I have that I would definitely recommend to everyone it's called what is it uh right here multiple cursor case Preserve so if you're selecting multiple instances and you're changing whatever that is it'll preserve the case as the the title says so it's really a really simple extension but probably one of the most helpful that I have installed so I would definitely recommend that now we're getting an error here typescript error because this takes in a weight so the weight isn't optional so I'm just going to add on to this so we got our subsets and let's go right before that and let's say weight like that and for the weight I'm going to do 400 okay so that should clear up that error uh enter is not defined that's because down here we now want to change that to robotto and there we go all right and then we might as well change this up the title here so I'll change that to expense tracker and for the description what do I want to say for this we'll just say track your expenses and create a budget create a budget all right so that's that we can exit this file for now so now everything's pretty simplified we just have this one our homepage which obviously is the root URL um so I think that before we do anything else why don't we create our neon database so I'm going to go to neon.pdf schema we're just going to add a new data source for postgres and include our database URL now there's a a concept of branching with neon which is really cool it allows you to manage your database branches like you'd manage your code branches and by default we get this this main branch which is automatically created for us and branches are great for development testing and various other purposes and they improve your productivity and optimize your your continuous integration and Del delivery pipelines so a branch is a copy on right clone of your data and you can create a branch from uh from a current or past state for example you can create a branch that includes all the data up to the current time or up to an earlier time and a branch is isolated from its originating data so you can play around with it you can modify it and then delete it when it's no longer needed now if you want to create a a Dev Branch for example you can just click this button right here and it will create for you but since this is such a a simple application I'm going to just stick with the the main branch and if you were to go to branches up here on the left you can you'll see a list of them we just have the main branch I'm going to click on that and by default if we go to rolles and databases we have a role of neon DB owner and a database of neon DB so what I'm going to do is create a new role and I'm just going to call it Brad but you can call it whatever and we'll create the role uh you can copy the password or download the EnV uh we don't need to do that right now so I'm just going to close out so now we have this rooll of Brad and then under databases I'm going to create a new database and I'm going to call this uh we'll call it expense uncore tracker and for the owner I'm going to select that Brad role and then create okay so now we have a new role and a new database and if we go to dashboard and we want to get the connection string for that we can choose expense tracker and choose Brad for the for the role and we can just click show password as well and here's our connection string so I'm going to copy that and then let's create a EnV for our environment variables and let's say database uncore URL and then we're going to paste that in all right so we have our our database URL now a couple other things I want to show you we're going to be using M uh Prisma migrations to actually create our tables and stuff but you can do it from within the the dashboard here so if we go to SQL editor and we go up to right here I want to select the expense tracker database and we'll just get rid of this so since it we're using postgres right neon uses postgres so we can write SQL here so let's just experiment and create a table so I'm going to say create table transactions and you don't have to do this because I'm just going to drop it afterwards I just want to show you how this works so create a table of transactions and let's say we want an ID field we want it to be serial primary key okay so that should just aut autoincrement be our primary key and then we'll have a text field called text which will be the type of text I like to make that uppercase and then the amount um amount will be say varar 11 and then created uncore at that would be a timestamp and we can make that have a default of the current uncore timestamp all right so let's see if we can run this so I'll click run and you see over here we have it in the history and if we go down to tables and we select the database expense tracker you can see we have our ID text amount and created at and from here you can add a record so you can add it that way or we can just go to the SQL editor make sure that you have the expense tracker Chosen and then let's do insert into transactions and we want to insert the text field and the amount okay and then we'll say value vales and I'm just going to just going to go on to the next line here and we'll do we'll do a couple different things so let's say paycheck so that's the text and then for the amount we'll say 500 and then we'll put a comma here and let's add another one so I want to add an expense let's say gas and the way this is going to work is if it's an expense then it's going to be a negative number so we'll say - 50 right and then let's say say we have dinner so we buy dinner and that's 100 bucks so that would be100 all right so let's go ahead and run that and if we go now to tables we should see if you choose the expense tracker database we see all three transactions with the autoincrement ID the text amount and the created at now I'm not going to keep this this table so let's go back into the editor and choose expense tracker and I'm just going to drop the uh drop the T the table so let's say drop table transactions and let's run that and now we we got rid of that because it's we're going to recreate it through our app through Prisma migrations so now let's uh let's jump back into our application we can go ahead and make that smaller and I'm going to install Prisma so so let's open up a new terminal cuz that one's running the dev server and we'll say npm install Das uppercase D Prisma and then once we do that we want to initialize a schema okay so it's installed now we can npx Prisma and a knit okay so by doing that it should create a this Prisma folder and inside of it we have a schema.
Prisma just make that a little smaller all right so we have our data source DB postgres we're looking at a a u a environment variable called database URL which we are we have right here that's our neon database so that's that's all set up now what we want to do is create our model so let's go down here and basically we're going to have two models one for users and one for for uh transactions and these models are going to be used with our migrations to create the actual database tables so we want to create all of our Fields here so let's say model user and the first field we'll have is an ID which will be of the type string I want it to be the primary key so we do that with at ID and then I want a default value of a uu ID so we can do that by passing in the uuid function okay and uuid stands for uh I forget what it is it's Universal Universal something identifier I forget um but yeah so that's going to be the the regular ID now in addition to that since we're using clerk we're going to the user is going to be created within Clerk and it will have its own ID there as well so I want to store that in the database too so let's call that clerk user ID okay now you can have clerk authentication without doing this without having the user store in your own database but we want that user information in our database we want the user's email name and stuff like that so that's going to be a string as well and I'm also going to just add at unique because obviously we don't want two users with the same clerk user ID then we're going to have the email so that's going to be a string and that's also going to be unique then we'll have the name and say string now name I'm going to say optional so we'll add a a question mark there and then image URL because when you use clerk you can have a an image so string oops that should be uppercase okay so name image URL let's do created at and that will be the type of date time and let's add a default so we'll say default and then we'll pass in now and let's do updated at that will also be a date time and we'll say at updated at and then we're going to have a relationship between models and transactions because when you log in you obviously you only want to see your transactions so they have we have to be linked so we're going to say transaction or transactions and we're going to set that to the type of transaction and it's going to be an array so we want our brackets and right now it's going to have a red line because transaction doesn't exist so let's do that next we'll create the transaction model so model transaction and then here we want again an ID it's going to be a string it's going to be primary key and we want a default of a uu ID and then we're going to have text so text will be string let's do amount and amount we'll store as float uh what else and then for the the relation to the user let say relation to user we're going to have the user ID for that transaction which is string and then we're going to have a user field and and this is where we want to create our relations so we're going to say user and then user with uppercase and then at relation and then our Fields so we pass in here fields and in Brackets user ID and then we want references and the reference we want to use is clerk user ID and then we can set on delete because if you delete a user then you're going to have transactions that belong to a user that doesn't exist so we want to make sure that we Cascade the delet so that if you do delete um a user then all of their transactions also get deleted all right and then after that we're going to just have a created at and that's going to be date time and we'll do a default of now and then we're going to add an index of for the user ID so we do double at signs and then index and then user ID all right so that should do it as far as our model and when we run our migration it should create the the table tables for us so we don't have to manually create them like we used to have to do back in the day with SQL databases okay so let's um so we modified the schema now we want to generate the client so we can do that let's jump into our terminal here and we're going to run npx Prisma close that up Prisma generate so whenever you Mo if you modify this if you add or change something you want to run this npx Prisma generate so Prisma schema loaded okay now we want to create our migration and run the migration so we can do npx and and then Prisma migrate Dev and that should create the the tables in neon okay enter a name for the migration let's just say user uh user transaction create now it says your database is now in sync with your schema now before you look at the database you'll see that a migrations folder was created and if we look at this file right here this is what was run create table user and it has all the fields that we have in our model and then create table transaction all the fields there any indexes any foreign keys so any relationships between you know the users and the transactions so that should have been run now let's check Neon so let's go to tables and if we choose our expense tracker database there we go we have our migrations and then we have this transaction which has the fields that we have in our model the including the user ID and then the user has all the fields that we have for our user model so our database is now set up and and ready to use so the only thing other thing I want to do before we move on to to set up Clerk and set up authentication and all that is create a file that we can use to interact with our database a file that will initialize the Prisma client so we're going to put that in the root we're going to have a folder called lib folder called lib Li and then in that we're going to have a file called db.
TS okay so here we can import the Prisma client okay and that's going to be from not that it's just Prisma Prisma Cent okay and then I'm going to declare a I'm going to say declare Global and V Prisma Prisma client or undefined so what I'm going to do here is kind of like a hack because nextjs has Hut reloading and we don't want the we don't want to initialize pris the Prisma client over and over so we have to kind of add this little hack here so we're going to say export const DB because we want this DB variable to be exported because that's what we're going to bring into our into our other files where we want to use the database and we're going to set that to let's say Global this do Prisma or new Prisma client okay and then we're just going to check to see if we're not in production because in production we just want to initialize it normally but if we're not in production then we want to uh we want to make sure that we don't initialize it multiple times with nextjs hot reloading so let's say process.
env. node EnV and we're going to check if it's not equal to to production and if not then we're going to say Global this. Prisma and set that to our DB okay so that's it in this file we don't have to touch at all but we can now bring in this DB variable and we can use it to to make queries whether we're adding something or updating fetching whatever it is we're doing so that's our main database file all right so now I want to start to set up clerk our authentication all right I know we haven't really done anything in our app yet but setting this stuff up first is going to make it easy for us to just to just create our components and do what we need to do uh I always I always think that well I shouldn't say always but in most cases I think it's good to just get your database stuff set up get your your your API keys and and all that that you need get that set up before you start building components so now let's install clerk so I'm going to go back to let's go down here clear that up and let's say npm install and it's going to be at clerk sln nextjs that's the package we want to install and then we're going to go to the clerk dashboard okay so we're going to sign in and everything here I'm doing you can do absolutely free so I'm going to sign in with GitHub and um I have this expense tracker Dev I don't want to use that so you're going to want to create a new application and over here is where well first off let's give it a name I'm just going to call it expense uncore tracker and then you can choose these different methods of of logging in so I want the defaults which are Google and email and password but you can also use GitHub Microsoft Dropbox all kinds of stuff here but that's all we're going to need so and our our login will look like this so let's click create application all right now what we want to do is let's see so we already installed it we already did this and then we need to set our environment variables which is going to be the public publishable key and the secret key so I'm going to click the copied I'm going to click the um clipboard thingy here and then let's let's go into ourv and paste that in so obviously yours will be different don't use mine mine won't even exist by the time you watch this but this should be your publishable key and secret key so let's save that close that up and then we it says update middleware TS so update your middleware file or create one at the root of your project and yeah so we want to copy that and go into the root here and we're going to create a file called middleware dots and then just paste that in so this will initialize the the clerk middleware and then the next thing is to add the provider to our app so we want that to go in the layout so if we want to use clerk we have to wrap everything in the provider so let's import that up here let's say import clerk provider and that's going to be from clerk SL nextjs and then we're going to put that in the return we're going to wrap everything in that clerk provider okay so let's take this ending tag and let's put that down here just like that and we should be all all set to to use clerk authentication that it's as easy as that to get set up so now why don't we create our header component because that's where I want to have the the login button so so uh let's see do we even have a components folder yet no we don't so let's create a folder called components and then a file called header.
TSX we'll say sfc so we're going to create a component called header and let's see in the return let's have a nav tag and I'm going to give it a class of navb now these classes are in the global CSS file that I've added so we're not going to have to worry about any writing any CSS and then we're going to have another div in that called navbar Dash container and this is you're going to see just how easy this is to have a signin button and sign out button so and and some options for settings so really cool stuff so let's have an just an H2 for our our logo thing so we'll just say tracker and then then we'll have a div so this will be on the other side and again it's already styled so basically I want to I want to import a couple things from clerk so let's import and this is going to be from and then at clerk sljs so what I want to bring in is going to be the sign in button and then signed in which we'll check to see if we're signed in and then then signed out and then user button and the user button is basically the little Avatar thing that you can click on to to you know log out and see your settings and so on all right so now in this div I'm going to use the signed out component so we want signed out and whatever I put in here is going to show if we're signed out if we're not logged in so what I want to show is the signin button all right then underneath that let's say if the user is signed in then let's show the user button all right so we'll save that and let's go back to our thing here and we have to obviously bring the header in now the header is going to go come into the layout because obviously we want this on every page so let's import the header from component at component slhe header and then we're going to put this let's see we have body let's go into the body and let's wrap this this children I'm going to have a main tag and actually I want Main and a class of container okay and then we'll move this children into the main and then above the main we'll have our head header oops header component okay so there we go so we have a signin button right I'm going to click on that and it's going to show us the sign in and I'm going to log in with one of my Google accounts here I'll use this Tech gu info click continue and that's it we're now logged in and you see the user button if I click that we have this drop down where we can sign out we have this manage account where you can update your profile you see your email address you can add additional email addresses you see your connected Google accounts so that was like nothing to have this functionality and to do this from scratch on your own would be a lot of work so really cool stuff so if I sign out it just signs me out and now I see my signin button again now the issue here is well not really an issue but it's not saving our user to our database it's clerk is working right that's all set up and you can you can add you know checks if you want to show something if the users logged in or whatever but we want to save that user in the database okay and doing that is is pretty simple and there's a lot of different ways to do this so initially I was going to use something called Web hooks to run a function when a user is created because you can do that and that takes some extra work because you need to make your app publicly accessible so when we're working locally like we are right now we would need to use something like enro and this is initially what I was going to do but I ran into some issues where I had to deal with uh opening ports on my router and I don't want you guys to have to do that I don't want to have a project that you know a quarter of the way through you can't continue because you have some firewall issue or whatever um so some things are just not great for tutorials even if even if that's the more common way to do it um but what we're going to do is something very simple we're just going to create a utility called check user and it's going to get the current user you know the logged in user the clerk user and see if that user is already in the database if it isn't then it's just going to add that user to the database okay and it's just going to return the user if it's already there it'll just get it and return it so let's put that in the lib folder so we going to create a file here we're going to call it check user.
TS all right and there's a couple ways that we can do this with clerk so I'm going to import this current user from clerk nextjs server and then we're going to also import our database remember that that db. TS file that's where we're going to use that well we're going to use it in a lot of different places but we're going to use it right here so let's say at SL lib slash and then DB okay so that's our database file and then we'll make this a function uh we want to export it too so let's say export const and we'll call this check user okay so we'll just make this an an async arrow function all right and then let's let's get the user so we can say cons user and set that to await so this is asynchronous so that's why we're using a sync await here and we want to get the current user all right then we want to check let's say check for current current logged in clerk user so we'll say if and then if not user then let's return null okay so if there's no user then we'll return null um then we want to check if and what I mean by that is it's checking clerk not checking our our database but we want to check if the user is already in the database so we can do that by let's say const log pluged in user and then we're going to await and then this is where we use our DB file so db.
user Dot and then I'm going to use find unique okay so these are methods that pris uh Prisma offers so find unique is going to take in a where Clause so we can say where and we want to compare the clerk user ID is that equal to the user. ID all right so that will tell us if the user is in the database and it will get it for it will get the user so now let's go underneath that and let's say if user or if user is in database then return user so if logged in user then we'll return logged in user and then let's say if not in database create the new user all right so for that let's say const and we'll just say new user and let's set that to await and then we're going to use our db.
user. create okay and that's going to take in a data object and what we want to add here is clerk user ID we're going to set to user. ID so user is the user that we get from clerk right so that's right here getting it from Clerk and we want to save that user ID as the clerk user ID and then in addition to that we want the name now what you get back from clerk is going to be you have a first name and a last name you could have first name and last name in your database as well but we just have just a name so what I'll do is add some back ticks and we'll take the user.
first name and then just a space and then we'll get the user dot uh user. last name okay so that will add the name to the database then the image URL so clerk also gives us an image URL field and then email is going to be user so what we get back here is this user email addresses because there can be multiple email addresses so I'm going to get the first one so it's the zero index and then email address and that's it so that should create a new user for us and then we just want to down here return new user and that should do it so just to reiterate we're getting the current user from clerk we're getting our database file we have a function called check user and then and we're exporting it we're getting the user if there's no user like if we're not logged in as I'm I am right now then it's going to return null uh then here we're checking if the user is in the database right because obviously if we pass this point there is a user so we're checking if it's in the database using the wear Clause if it is we're just going to return the user if not we're going to create the new user with the fields from Clerk and then we're going to return the new user all right so now what we'll do is go into the header and the header is loaded on every page right it's in the layout so even though this is just a one-page project but even if there were multiple pages so let's bring in check user uh yeah so bring in check user from lib check user and then all I'm going to do is in the header I'm going to make this async okay this is technically a server component runs on the server so let's say cons user and set that to await check user so that's going to run it all right so I'm going to go ahead and save that and just to make sure that that's actually running let's come up here and let's console log user and we'll save that and remember this is a server component so it's going to show in this console which you can see right there null if I reload there and it also shows it in my editor I think that's the turbo console extension that I'm using that does that um but yeah so that's null obviously because we're not logged in so let's click sign in and I'm going to just use Google I'll use this Tech Guy info and what should happen is it'll log me in just like before but now it's going to get saved to the database and you can see my console log now is this so this is the stuff that I get back from clerk the the ID updated at image URL has image primary email address so all this stuff you have access to this is the email addresses object um what else phone numbers so you get a ton of stuff here to work with now for the moment of truth let's see if it was actually added to the database so we're going to go back to Neon and user I'm going to reload the page and make sure I choose expense tracker and there we go so we have all the user data we have the ID so that's just the our you know our database ID the clerk user ID the email the name the image URL created at and updated at okay so anytime a user signs in in with either Google or through email you know they sign up with email and password it's going to get added to the database and that new user file a check user file is going to always check to see if the user is logged in or not and it'll get the user so I'm just going to get rid of that console log so yeah I mean with the little bit the little amount of code that we've written we have some really cool functionality okay now we're gonna just basically just show a message with a signin button if the user is not logged in so let's go ahead and log out sign out and I'm just going to do this in a very simple way we're just going to have a component called guest.
TSX and let's just do let's see we're sfc and we'll call this guest and then as far as what we want to return let's just have a a div with the class name of guest and we'll have an H1 we say welcome we'll have a paragraph and we'll say please please sign in to manage your expenses or let's say manage your transactions and then we can just add the signin button by bringing it in so sign uh what is it sign in button from Clerk and then we'll just put that right under the paragraph So sign in button all right so now let's Go's see let's go to our homepage because that's where we want to show it so it's this page.
TSX and let's bring in say import guest and then I'm also going to import the current user and let's go uh this homepage component let's make this a sync and then we'll say con user set await current user and then all I'm going to do is before this return I'm going to check to see if not user and if not user then let's return guest so ve very simple way of doing it and then if if there is a user let's change this this uh expense tracker heading here instead of that let's say welcome and we should have access to the user's name so user is coming from clerk so we have access to first name so let's just do that for now and now we can click either of these buttons to sign in just going to hit that and techi info continue and there we go welcome Brad okay so that's that now what's the next thing now we can start to work on our transaction components we have everything set up as far as basic authentication as far as the database goes and our models and tables so let's start off with the add transaction component because I want to be able to have a form where we can add our transaction and get that sent to the database so let's create in components a new file called add transaction.
TSX and we'll do sfc add transaction and then in the return here let's just add a fragment and let's do an H we'll do an H3 add transaction and then we're going to have our form now our form we're going to be using server actions however I don't want this to go directly to a server action because uh I want to do some validation and in order to do that we're going to have it go to a client action because you can now have actions on your client as well and this is going to be a client component in fact we have to add to the top use client like that or not like that like that okay so what I'm going to do is have the action go to a function called client uh client action like that and we'll add this so we don't get an error we'll go right above the return and let's say const client action and we'll set that to an arrow function and for now let's just do const uh not const console I'm just going to do a console log and I should be able to get the form data uh wait a minute we need to do a couple things here we need to first of all this needs to be async and then it's going to take in form data which is going to have a type of form data uppercase F and d and then in the console log let's do form data doget and we're going to get the text field and then I'm just going to put a comma and then we'll do form data.
get and we want to get the amount okay because we can do this now because of these actions which is really cool and then we'll call our server action from here because obviously when we when we add the transaction we're going to be using Prisma and that's that's obviously backend stuff you're not going to do that within the client but there is some stuff I do want to do in the client that's why I'm having it go here first all right so now in the form let's have a class of form control and let's have a label and this is going to be for the text so we'll say text and let's see have an input and let's give that an ID of text a type of text and also a name of text because that's how that's how we're getting it here this form.
datag get is going to look at the name name of the input fields and then we'll have a placeholder as well and just say enter uh we'll just say enter text dot dot dot okay now let's go under that div and add another form control div and then we'll have another label let's close uh close a sidebar up so this is going to be for amount and in the label for amount we're going to say amount and then I'm going to put a line break and then I just want to put in parth es that negative uh so negative is an expense and positive is income just to let the user know and then input let's do a type of number and a name of amount and ID of amount and a placeholder of enter amount and then also if you if you have a number field it's not going to allow decimals by default but you can change that by adding a step of 0.01 uh no zero yeah Z 0.01 and then it should be able to have um decimals okay so under that last div let's add a button give it a class of BTN and we'll we'll just say add transaction all right so let's bring this in now to our P our homepage so app page.
TSX we're going to import add transaction and we're going to put this right below the H1 add transaction and there's our component okay we got our text field we got our amount we should be able to do like $4.99 cool now if I submit this and I look in um oh this is on the client that's right remember we said use client and you can see right here uh s SWS which is the text in 499 so this is a client component however we want to submit it to a server action so let's create that let's go to app add a new folder called actions and we'll add a new file and let's call this what do I want to call this uh we'll just call it add transactions and that's going to be a TS file or add transaction so singular so add transaction.
TS now with the server action we're going to put at the top here use server instead of use client okay so this is this is only going to run on the server and then let's we're going to have a function called add transaction and it's going to return a promise with a transaction result so since we're using typescript let's add an interface so we'll create an interface I'm going to call this transaction data and this is going to have text which is going to be a string and it's going to have amount number all right then we're going to have another interface call and if you're not using Tri typescript you don't have to do this but let's say transaction result and the result is going to be either it's going to have data and I'm going to put a question mark because it could be an error but what we what we are expecting is data and that will have the type of transaction data dat okay then we could have an error as well again we want to make that optional so question mark and that would be a string so this function that we're about to create is going to return either the data which will have the transaction data or an error which will be a string and we're returning the error because we want to be able to show it in the UI if there is an error so now let's create the function so we're going to say async function transaction and it's going to take in form data so let's say form data with the type of form data and then what it's going to return is a promise and that promise is going to have a type of result now I want to get the data from the form data and check I want to do a little bit of error checking or validation and then send back either the transaction if everything's okay or the error if there's an error we're not going to do anything to do with the user yet or anything to do with the database I just want to get that part of this working so let's create a variable we'll call this uh let's say text value uppercase V value and let's set that to form form data.
getet and then text okay and then we'll do the same for amount so let's say amount value and that's going to be form data. getet amount all right then we're going to let's say check for input values so I'm if uh if not text value or the text value is equal to nothing just an empty string or not amount value value okay so if if that if any of those are true then what we want to return is going to be an error which will be a string and we'll say text or amount is missing okay because remember we can return from this function either uh either error or data so in this case we're returning error and then next thing I'm going to do is ensure that the text is a string so let's say const text and type that as string and then we're going to say text value and then do2 string okay so that will ensure ensure text is a string and then let's do const amount and we want amount to be number so let's set that and we're going to use the parse float function and then pass in amount value.
to string okay so we'll say parse amount as number okay so we're just formatting it and making sure it's how it's supposed to be before it goes in the database now let's create uh an object called data oops lowercase T lowercase T because we want to set that to the type of transaction data uppercase t set that to an object which is going to be text and amount all right and then the last thing I want to do here is just return so as long as there's no errors then we're going to return that data which is going to be our transaction data so that should satisfy everything as far as the promise that we're returning with the transaction result and so on now we want to make sure we export this function so down at the bottom I'm going to export it as default add transaction now let's go back to the add transaction component and go into the client action cuz that's where we want to call the function we just created we don't want this console log anymore what we want to do is create a variable to hold the result of the server action so we're going to set that to uh let's set that to await because remember it returns a promise add transaction which I'm we have to import which it just it auto imported for us sorry about that Discord so we're importing add transaction and then we're setting it to uh that result variable and we want to pass in here remember it takes in if we look right here it takes in form data so we're just going to get the form data here and then pass it in like that okay so that will give us a result and that result is going to be either data or error remember that's the transaction result it's going to be either data or error so let's check for the error so we'll say if the result.
error we could do it like this or we could just uh we could just destructure this and say data error and let's say if error either way it doesn't matter whatever you want to do so if error then let's alert and I'm going to not going to keep the alert we're going to use a toast and make it look better but just for now we're going to use an alert and then else we'll say say alert and just say transaction added even though it's really not we haven't done any database stuff yet but we'll just do that and then I also want to just console log the data okay so at least we can just try this out so far I'm just going to reload this okay and let's say like uh paycheck paycheck 400 and add so we get trans action added and if we look at the console log we get text paycheck and amount 400 all right so again what happened is the form submitted to this client action but then from there we called add transaction passed in the form data got back a promise and got this data or error in this case no error so it just alerted transaction added and then console log the data okay okay if I try to submit this without anything then I get text or amount is missing right and yeah we just got it's just an alert of the error so now before we um before we add it to the database we need to get our user because we need to uh add the user ID with the transaction so it knows which user added that transaction now within our AC s to get the to get the logged in user we're going to import off from clerk nextjs server we're going to do this a little bit different than um than current user this was actually suggested to me by the devs so down here uh let's see where do we want to do this let's just go under all this validation stuff and let's say check uh or let's say get logged in user and we can actually extract the user ID from that off okay so user ID from off and we can try it out just to make sure oops just to make sure we're actually getting it let's say user ID and this should log down here because this is a server server action so we'll just put whatever okay transaction added and then down here you can see our user ID so we want to make sure that that user ID goes into the database when we do our our dat our Prisma call all right um but first we want to check for the user and if there isn't a user then we want to return an error so right under that let's say check for user and we'll say if no user ID then let's return error because remember we can return an error which is a string and we'll say user not found okay and that should do it as far as getting the user now we want to actually before we do the database why don't we get the toast set up instead of doing these alerts so I'm going to go to the the other tab here in my terminal and let's npm install react Das toasttify and if you've watched in any of my other react tutorials chances are you've seen me use this before it just gives us nice looking uh call outs or nice looking toast components instead of having an ugly alert now in order to use this in our layout we have to Output the toast container so let's go to layout TSX and at the very top we're going to import two things one we need the toast container from react toasttify and we also need the CSS file which is going to be uh react Dash toastify slist slash and then react I believe it's yeah react toasttify docss okay and then we need to Output this this toast container down here in our layout output so we can put it just right above the ending body tag so toast container like that now from any component we should be able to import toast we want to be in the component not uh not the the server action so here let's import and like that so import toast from whoa from ah react Dash toasttify and then let's see where we want to call this is going to be right here instead of alert let's toast.
error and then pass in that error and we can just get rid of the alert here this is ultimately um we're just going to redirect or or refresh but for now we'll just leave that I just want to make sure if we get an error there we go texture amount is missing so that looks much nicer than the alert all right so now the final thing we want to do for this component this whole part of the application is is save it to the database so we're going to do that in the server obviously so add transaction TS and let's see we're going to import a couple things here one is going to be the DB that's what we whenever we want to use the database we're going to bring in that file and then we're going to bring in something else called revalidate path because once we actually um once we actually submit the transaction we basically need to to the app to refresh and this is going to do that for us this revalidate path it's going to be from next cache okay so now let's go down to where we have this transaction data and let's see I'm actually going to change this now to equal get rid of that so let's have this equal a weight and then DB do transaction and then do create and that create is going to take in an object with a data object and that data object will have the text so it'll have the text it'll have the amount and the user ID all right and then actually you know what we should put this in a try catch so let's do this try oops try catch and I'm going to move this and the return just going to cut that and put that into the try all right so now we have transaction data now in between these two is where I want to call revalidate Path and then just pass in pass in slash so that way we don't have to refresh the page once it gets added to the database and then if there's a problem so in the catch then we'll simply return uh we'll return an error which will be a string and we'll just say transaction transaction not added all right all right so I think that should do it so again it's just getting the form data passed in we're getting the text and amount validating it a little bit we're checking uh making it making sure it's a string and a number getting the user ID creating the transaction with the text amount user ID and then we're returning the transaction data now let's go to the component and I'm just going to have a toast let's say toast.
success s and we'll transaction uh yeah transaction added okay so let's try that out and hopefully it works if it works it's going to go into the database so let's paycheck 500 add we get transaction added we obviously can't see it in the application yet because we haven't added that component but we will have a list of transactions but let's go ahead and check the database so I'm going to reload the page here and choose expense tracker and we have our user we know that already and there's our transaction it has its own ID it has the text of paycheck amount 500 it knows what user added it and created at awesome so that's working as expected now one thing I would like to do is clear the form so we can do that by using use ref so I'm just going to go up to the very top here and just say import and use ref which is just a react hook so that's going to be from react and then let's go right in the add transaction and we'll say const I'll call this form ref set that to use ref and I'm just going to add here for typescript HTM ml form element and null and then what we can do is we need to attach this form ref to the form so right here let's say ref set that to form ref and then just right after the success we can take that form ref and we can say dot current and then do reset okay so that should clear it so let's add let's say dinner we'll say negative 50 let's try a decimal so we'll say negative U 4998 add transaction okay then we're going to just go check it reload expense tracker and there it is dinner and it has the negative 4998 and it has our user cool so our whole add transaction functionality should be complete so the next thing I'd like to do is show the balance right so we'll have a balance component but this is going to be the flow of of the rest of our application creating the component creating the action whether it's an action of well we have no more forms that'll be submitted so it won't be a form action but for instance we get the user balance we'll have an action that will reach out to the database with Prisma get that balance and then send it to the component so we can close all these tabs up and we're going to create a new component and we'll call this we'll just call it balance.
TSX and in Balance where this is going to be pretty simple so let's just do sfc and call call it balance and let's see in the return we're going to have just a fragment with an H4 and we'll say your balance and then under that will be an H1 and this is where we want to put the balance but for now I'm just going to put I'm just going to hard code 500 because I just want to bring it in so we're going to bring it into page. TSX the homepage and let's go right under add transaction and we'll import balance and let's go down here and I'm just going to change the H1 to an H2 and let's put the balance right under the H2 and above add transaction okay so there we go your balance 500 now we want to get that balance from the database and we can do that by using a simple reduce method on the transactions so let's go into actions create a new file here called what do we want to call this get we'll say get user balance.
TS and then from here we want to mark this as use server and then we want to bring in our database so import DB from lib DB and we're also going to import off and that's going to be from clerk next JS server oops all right now let's create a function so we'll say async function and I'm going to call this get balance and then as far as what we're going to get from this it's going to be a promise and it'll be an object with the balance which will be a number and we can also get an error which will be a string all right uh whoops I forgot my quotes not my quotes my what is this thing colon okay so in the function here let's get the the user ID remember we can get that from off so we can destructure and get user ID from off and then we'll check for the user so if not ID then let's return an error and we'll say user not found all right and then if there is a user then we're going to open up a TR catch and in the TR catch I want to first get the transactions of the user transactions set that to await and we're going to use db.
transaction dot uh and then there's a method called find many okay and we can pass in there an object with a where Clause so with where we want to find where the user ID is equal to user ID all right and then let's see after that to in order to get the balance what we can do is we can take our transactions that we just fetched from the database and we can use reduce reduce is going to take in a function and that's going to take in let's say sum so the accumulator and then transaction and basically we just want to take the sum and we want to add the transaction do amount and then we just want to put the starting point which is zero so that should actually give us the balance and then we can return balance and if something goes wrong then we'll return an error and we'll just say uh what should we say database error I guess and then let's export this so export get user balance and yeah I think that that should do oh we want to export as default all right cool so let's go back into the balance component now and let's bring this in so up at the top we want to import get user balance and then how do we want to do this um so right here we should be able to say uh balance and we need to make this a sync because this is going to be a synchronous so await on get user balance all right and that should give us the balance and then come down here and let's get rid of the 500 and let's put in the balance all right undefined string is not assignable to type react node um what did I do wrong here oh this should be we're destructuring this okay and there we go 450 O2 now if we look at what we have as far as transactions if we go to our database so we got a paycheck for 500 and we got dinner for $49.98 so 500 minus 4998 is going to be 4502 now a couple things I want to do before we move on where we have the balance I'm going to use the nullish coalescing operator and put zero here so basically what this means is if whatever is on the left is null then it'll be the value on the right so if no balance it'll be zero and I'd also like to add commas if it's in the thousands so for instance if we say let's say paycheck two and we'll say it's for $800 and then we add that okay it gets added but I'd like to have commas in the thousands places so why don't we create a utility function for that and you could do this a million different ways but I'm going to go into the lib folder and create a file called utils.py okay and then what I'll do is return the whatever X is do2 string and then I want to do do replace and that takes in a regular expression uh actually we don't need quotes we need double forward slash now the regular expression I'm going to paste in I basically just use chat GPT for this just to get this expression to replace the commas where the thousands places so I'm going to paste that in we want it to be Global so we're going to add a g and then the second argument is going to be a comma whatever the character that you want to insert in the thousands places all right and then that should do it so I'm going to save that and then let's bring that into the component so import add commas and then down here we have the balance let's do add commas and we want to wrap the balance and the question marks in the zero okay so now if we check it out now we have a thand we have the comma where it's supposed to be now we're going to move on in a second but one thing I forgot to show you is if we go to our clerk dashboard you're going to see all your users okay so if I go to users I mean I only have one but you can see the user I mean if you were taking phone numbers you'd see that but we just have the email account we have the name we have the user image the user ID D so you'll be able to to check all your users from here and there's all types of other stuff you can do you can have you know organizations um and you can obviously change up the way that they log in if you want to add different uh like Facebook Twitter and GitHub and other ways of of validating you can do that as well uh but yeah I just wanted to show you that so now I want to have a spot where it shows the income and expenses cuz right now it shows the balance but I also want wanted to show how much income we have and how much expenses so we'll have another component and we're going to call that let's call it uh income what should we call what did I call it income expense.
TSX and we'll say sfc whoops sfc and income expense and let's return uh div I'm going to give it a class of in c-- container and then inside that we'll have a div and an H4 in that div where it says income and then we'll have a paragraph with the class of money and the class of plus and let's say for now we'll just put $700 I'm just going to hard code it for now and then outside of that div we're going to have another div and that's where we'll have an H4 with expenses or expense and let's do a paragraph with money uh money and then a class of minus and for that we'll just say 200 again just hardcoding it for now and then let's put it into the homepage so I'm going to bring in import income expense and where we going to put this we're going to go right balance okay so if we check it out that's what it looks like now we want to make this real so we want this to to come from our database so basically what we have to do is find all the positives add them together to be the income and then all the negatives and add those together that will be the expense so let's create another action and we'll call this get income expense.
TS or expenses or no we can leave it singular get income expense now we can probably copy from the the uh get user balance action probably just copy all this because it's kind of similar doing a lot of the same stuff so we'll paste that in we're setting it use server we're getting the database getting the off let's change the name of the function to get income expense and for the promise we're going to this is going to have income so income which will be a number and also expense which will be a number and then a possible error and then here I same thing we're getting the user ID we're checking for the user and then we want to get the transactions just like we did here but we're going to change some of this stuff up so let's get rid of that and what we want to do is first get the let's get the amounts so I'm going to say amounts and set that to transactions oops so we're getting transactions and then we'll use map and basically we're going to just get the just the amount because remember transaction is an object that has text amount ID user ID we just want the amount that's all we're dealing with so in the app let's add a function and we'll say for each transaction we just want to return the transaction.
amount okay so that'll give us the amounts now after that let's get income so we can take the amount or amounts and we can use yeah let's use filter and we just want want we basically we just want the positive right because the income is going to be positive num so in filter let's pass in a function and we'll say for each item we want a filter where item is greater than zero let me put this filter on a separate line so we'll do filter and then I'm going to use reduce and add an accumulator and the item um and then oops forgot my parenthesis so accumulator item and then what we can do is take that accumulator and just add the item because all we're doing here is adding all the the the incomes together and we want to start at zero all right so that'll give us the income then we want to do the expense so I could just I could just take this copy it down change this expense and instead of we want to do filter but instead of item greater than zero we want to do item less than zero because we want the negatives and then same thing we're just going to add all those together so that'll give us the expenses now in the return instead of balance we want to get rid of that instead of balance we're going to have income and we're going to have expense um however expense I want to just wrap it in math.
absolute or math.abs and then expense okay and then if there's an error we'll just say database error that's fine and then for the the export it's going to be get income expense so now let's go back to the component and let's bring in the acttion so we want to income uh what is it is it get income expense and then we can get both the income and expense from that so income expense from and we just want to make this a sync and then a weit and get income expense okay and then we're just going to come down here and replace the hardcoded numbers this one is going to be for income and this one is going to be for expense save that there we go we got 1300 income and 4998 expense and actually let's take a look here let me just reload this so yeah we got 800 and 500 which is going to be 1300 and then 4998 so that's working so the workflow is is very similar with all this stuff now finally we want to list the each transaction so let's create a new component and we're going to have a component called transaction list and transaction item for for this the individual item all right so let's uh let's create the list first so transaction list.
TSX sfc transaction list and let's see we're going to uh how we going to do this let's just have a fragment and then we'll have an H3 and we'll say history underneath that we're going to have an unordered list with a class of list and basically I want to fetch the transactions Loop through them or map through them create a list and then have the individual transaction item component but for now we'll just output like the a paragraph with the with the text so I know we don't have the transactions yet but we will we'll create an action to get those so I'm just going to type out the code so transactions and let's say if there's transactions then we want to map oops read transactions.
map and let's say for each transaction now we're going to have a type of transaction so I we'll create those in a minute too um and then let's have our arrow and then open up some parentheses and for now like I said we're just going to have a paragraph with the transaction. text all right so that's going to give us an error well it's not because it's not even in the the the app yet but let's bring it in so I'll go into page TSX and let's import transaction list and we're going to put this at the bottom so right under the form the add transactions so transaction list and now we're going to get an error now before we we go in and we create our action let's create the type for TR uh transactions so I'm going to create a folder in the root called types and let's create a file and call this transaction.
TS okay and this is going to be pretty simple we're just going to export an interface and call this transaction and it's going to have have an ID string text string amount number um user ID string and created at date that's it so we can close that up and now let's bring that into where were we into our page. TSX because no not our page. TSX where were we um transaction list cuz we're using it right here so up at the top let's um transaction and that's going to be types okay so we get that now we need this we need our transactions so we're going to have a new action file called transactions so new file get transactions.
TSX so basically instead of API routes we're using using these server actions which I I I personally like and actually if you took my nextjs from scratch course the one I released a couple months ago we used API routes but I'm actually refactoring it to use actions instead and that should be released um probably a month or two so let's say use server I don't know why I keep saying user server and let's import the actually you know what let's just copy one of these we'll copy um the balance all right so let's change this transactions and let's see it's going to return let's change balance transactions and that's going to be we can bring in the type as well that we just created so import transaction from types and this is going to be transaction but it's going to be an array so we want to put our brackets and then also a possible error and then we're going to get the user check for the user and then we're going to call find many so we're doing the same thing here we want to get only the user ID's transaction we don't need this balance get rid of that but in addition I want to order it I want to order it by date in descending so what we can do is after the wear we can say order by and say we want to order by created at and we want to do descending right and then we're just going to return instead of balance we're going to return transactions all right now make sure we too so get transactions now we can bring it into the transaction list let's go right here import transactions and we'll go right here cons so isn't this better than use effects I I personally like like this a lot better than doing the the whole use effect thing uh let's see so I'm going to extract the transactions so transactions and error and let's set that to await get transactions which we need to make this asynchronous okay and then yeah I mean that should do it let's check for the error though so if we'll say if there's an error then let's return a paragraph and we'll give that a class of error and then just output the error okay so down here history we got paycheck to dinner paycheck so right now it's only showing a paragraph with the transaction text but obviously we want that to be its own component so let's create now um we can close up the get income expenses we can close up get transactions I think we have all of our components on the page we can close up page for now and income expense and then let's create a new component so in components we're going to have transaction item.
TSX all right and a few things we're going to bring in so we're going to bring in the type of transaction so bring that in from types and then we're also going to wh we're also going to bring in the add commas and we're also going to bring in toast because we're we're going to have a delete button so I just wanted to show a toast that says it's deleted and then let's say sfc and transaction item it's going to have a prop of transaction that's going to get passed in so let's set that to the type of and then transaction colon and then transaction so we're using our type here all right and then in the return we're going to have list items so let's say lii now I want to have a class of minus if it's a negative if it's an expense and a class of plus if it's a a an income a positive number so what we can do is add a dynamic class name so set this to curly braces and we'll use a turn AR so we'll say if transaction do amount if that is less than zero okay so it's negative then we want a class of minus else we want a class of plus and then inside the LI let's have the transaction text okay and then underneath that we're going to have a span and in that span we'll put let's use our add commas so add commas and then inside that I'm just going to pass math ABS so that will get the absolute number of amount and I'm just going to we have more stuff to add to this but I want to just um just use this for now so we'll go back to the transaction list component and up at the top let's bring in transaction item and then we'll go down here and where we have this paragraph we're going to delete that and put in our item and since it's a in a list we have to pass in a key and the key we're going to set that to ID and then pass in transaction and transaction save that and there we go so the reason you see the green for the the income and red for the expenses is because of this the plus and minus class all right cool now I'd also like to have the sign and if it's a positive it'll say plus if it's negative it'll have a minus so let's go into the the function but up at the very top above the return and let's create a variable sign and we'll just set that to let's say transaction.
amount if that's if that's less than Z then let's show a minus else let's show a plus and then down here right before let's see we're going to go right before the let's have the number sign here as well and then before that is where we'll put the sign so now you can see we have plus 800 and then minus 4998 now the last thing I want to do in here is the the delete so we'll have to have the delete functionality the delete event and then have uh an action to actually do the delete from the database so let's uh yeah let's add the button so under span We'll add a button and we're just going to have an X in the the button and then let's add an onclick and we'll set that to a function and we're going to call a function called handle delete transaction and that's going to take in ID all right and then we're also going to add a class name so let's go outside of this curly brace here and then add a class name of delete - BTN and we have to create that handle delete transaction so let's go up above we'll go right under the sign variable handle handle delete transaction and we want to make this a sync and then this is going to take in transaction ID string all right and I I do want to have just a a confirmation so let's const confirmed and we'll set that to window.
confirm and let's say are you sure you want to delete this transaction all right and then we'll check that confirmed so if if not confirmed then we'll just return okay and then we're going to await on a function called delete transaction which we haven't created yet but we will and then that's going to take in the transaction ID and then after that we'll just do a toast. success deleted all right so obviously this delete transaction doesn't exist so we're going to create a new action so in the actions folder create a new file delete transaction.
TS and I'm just going to copy the user balance action whoops and we'll paste that in here and let's just change some things uh we do want to import the revalidate path because once we delete it's not going to update automatically unless we call this so let's say revalidate path from next cache and then let's change the function name so a what I do change the function name to delete transaction and that's going to take in transaction ID okay and then the promise that we return we'll just we'll just do a message string and get the ID check the ID and then in the try let's get rid of this stuff and what we're going to do is just await on DB do delete pass in an object and add our wear and we want to say where the ID is equal to the transaction ID and also where the user ID is equal to user ID all right then we want to just revalidate path just slash and then what we want to return we'll just return message yeah we'll say mage message and deleted okay that's it now let's go back into the item component and bring that in so import delete trans oh I didn't export it did I yeah we get the wrong thing exported so export that then we want to that okay um now we're not doing anything with the message that's returned so we could do const we could do message and error and we can we could do if error then I guess we'll just uh we'll do a toast.
error and pass in the error and then down here if there's not if there's not an error then we'll just say success but we can actually pass the message in that comes back from the server so that would be just message all right so let's see is this work event handlers cannot be passed to client component props um did I use CL oh yeah this has to be a client use client all right cool so if we come down here when I hover over it you see there's a delete button so I'm going to delete the let's just add another transaction I'll just say test and we'll say 300 okay so that gets added I don't even think we we tested that yet didn't we to see if if that showed up so it shows up test let's go ahead and click delete it's going to confirm let's click okay and we get transaction deleted and it goes away now it's just a couple small things that I wanted to…
Transcript truncated. Watch the full video for the complete content.
More from Traversy Media
Get daily recaps from
Traversy Media
AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.









