Now that we have converted our transactions and points into usable hooks let's go ahead and let's create the transaction page and let's create a drawer which is going to open so that we can create a new transaction. We're gonna start by going inside of Features, Transaction hooks right here and let's change this Use new account to Use new transaction. Inside of here I'm going to also rename the function. So I'm gonna rename all instances of account to transaction and the rest can stay the same. And then inside of components Let's go ahead and let's rename a new account to new transaction Whoops And let's do the same rename inside of the component.
So it's not going to be new account but new transaction. Now let's go ahead and find the insert account schema import and let's remove it so we know where we have an error here and let's import insert transaction schema here instead. So this will be a slight modification. Let's use this insert transaction schema but instead of pick name it's going to be omit ID true. Like that.
So now we have this error here for the values. So let's go step by step. First, let's resolve this. We are no longer using use new account. So find that import and remove it in favor of use new transaction, which we've just renamed like that.
Next, we have use create account. Well, first of all, let's use use new transaction here. And in order to fix this values here, we have to change this mutation. So right now it is use create account. Let's remove that in favor of use create transaction, again from add features transactions like that.
So we created this in the previous chapter and let's use it here and I have some TypeScript error I think if I just reload my window It's going to go away and there we go, we no longer have any errors here besides in our form here. So that's why I'm going to remove the form from now and just write a paragraph to do transaction form. Let's change this to say new transaction and let's change the description to say add a new transaction. There we go and we can remove the import from account form as we are not going to need it at this moment here. So we can just leave the on submit function be unused.
Now let's go ahead and close everything and let's go inside of our providers sheet provider. I'm going to add a little space here and let's import new transaction sheet from features transaction components new transactions sheet. So the component we just modified, make sure you have renamed it here, otherwise you won't get an import. So I'm gonna add it here. There we go.
And now it can be opened. So Now we are ready to go ahead and go inside of app folder, dashboard and let's create a new folder transactions here. Actually what we can do is we can copy the accounts, that's easier. So let's go ahead and copy accounts and write transactions. Like that.
Let's go inside of page.tsx and let's rename this and the default export to transactions page. There we go. So now if you try and go into transactions it's going to load accounts because we just copied that. Again, if you are getting a 404 here, confirm inside of your navigation that your transaction href matches the new folder we've just created transactions here. Make sure there are no typos or misspellings.
Great, let's go ahead and let's modify this from accounts page to transaction history. And let's go ahead now and slightly modify the rest of the stuff here. So what I'm going to do is first of all, okay, we have some TypeScript errors again. This is just some weird TypeScript server, which happens when I copy a lot of stuff, right? So when I just reload my window or shut down VS Code, they go away.
So let's start with this, New account, use new account. We are no longer using that. Instead we're using use new transaction from features, transactions. So let's replace that here and instead of new account is going to be new transaction. And the errors are going to tell us where we need to change it.
So right here, new transaction. There we go. So now if I go ahead and click add new, there we go. New transaction to do transaction form. Perfect.
So that's exactly what I wanted to achieve. So for now we can leave everything else as it is. We can leave use bulk delete accounts all of these things. We're gonna come back to this later because what I want to wrap up now is what we started and that is the form. So go back inside of Features, Transactions, Components, New Transaction Sheet.
So first of all, before we can even start creating this component, we need to load some options for it, right? So I don't want to use the form component to load options inside. I want to use this parent component which will render the form to prepare all the options. So what options am I talking about? The category options and account options.
So that's going to be shown in a drop-down, but we first need to fetch it because every user has its own options. So let's go ahead and do const category mutation to be use create category. So that's going to be from features API use create category. I'm going to add that here. I'm going to separate the features so it's visually more pleasant to see.
Then let's write const category query here to be use get categories. Again I'm going to align my imports here and then we're going to have const onCreateCategory to be a very simple method which accepts the name which is a string and simply calls the category mutation.mutate() and passes in the name and then we're gonna have const category options which are going to be a very simple check of category query.data?emptyArray() so if there is no data we're going to work with an empty array and then we can safely do dot map here we can get the individual category and we're going to transform it by returning an immediate object from this dot map into label category name and value category dot id. There we go. So you should have the name and you should have the id. That's why inside of our categories API route when we get all of them in here we are returning the id as well as the name because we need it right here.
There we go. So now we can copy and paste this and we can do the same thing for account query. So this will be account query use get accounts. Let me go ahead and fix this import here. So I'm going to add it to the top here, but I'm going to separate it from categories.
All right. So let's see which ones are the originals. This is the original, this is the new one. So the second one is not category mutation but account mutation and that will be use create account. So let me go ahead and align the import here as well so I have them all in one place.
Then we have on create account to use the account mutation.update and name is the same. And lastly, we have the account options, which will use the accountQuery.data. And this will not be category, but account. There we go. So now we are ready to pass these as values for our form.
But we don't have the form yet. So let's go ahead and let's prepare the form. So inside of account form, let's change this to be transaction form like this. And then let's rename the component itself to also be transaction form like that. And now we can go back inside of the new transaction sheet component and we can import the new transaction, my apologies, transaction form rom.slash transaction form but I am going to change that to Features, Transactions, Components, simply so I can keep all of them right here together, there we go.
Great, So now that we have that, let's go ahead and let's pass in all the props that we now have inside of here. So that's going to be onSubmit, onSubmit, it's going to be disabled. Let's put it false for now. We're gonna have category options which are going to be category options. Then we're gonna have onCreateCategory to be onCreateCategory And then we're gonna have account options to be account options.
And on create account is going to be on create account. Like that. So we're gonna have to adapt our transaction form a bit to accept all of those. And first let's resolve this disabled state so we can do that by introducing a constant is pending and it's going to check if our first mutation here so this mutation let's rename it create mutation actually so it's more implicit Again I have to reload my Windows so it restarts the TypeScript server. There we go.
So I just renamed this to create mutation and now inside of my onSubmit I'm also gonna change this to create mutation. And now inside of isPending let's add if createMutation isPending or if categoryMutation isPending or if accountMutation isPending like that So that's our isPending here and let's now add const isLoading. So isPending will disable the form whereas isLoading will not even show the form. So we are going to show the loading status if we are loading our category options. So we're going to do category query is loading or if account query is loading.
Like that. So now we can do the following. We can replace the disabled with is pending and we can also do the following. We can check if is loading. In that case, we're gonna show one thing.
Otherwise we're gonna show this transaction form so let's move it inside of the other if clause or the else right and now in the first one we're gonna add a very simple div with a class name here which is going to be absolute in set zero flex items center justify center and inside we're gonna use a loader to from Lucid React with a class name of size 4 text muted foreground and animate spin so just ensure you've added loader2 from Lucid React I'm gonna keep it here at the top with my Zod. And let's see if I can just align this better. Actually this is fine. Great. So now we are ready to show our transaction form.
And you should now see, let me go ahead and if I refresh here, and if I click here, well, it loads immediately, right? But if it weren't loaded, right? If these options were not ready, the category options and the account options, then it would show a little loading indicator before it loaded the form. So now let's go inside of this transaction form which we've just created. So transaction form and we have to modify, well first of all the form schema and then we have to extend the props a bit.
So let's start with the form schema. So the thing with form schema here is that we have to kind of create it, we have to modify it a bit. So it's actually easier for us to write it out from scratch than to try and modify the one from Drizzle because there aren't exactly options to override in the way we specifically want to. So let's go ahead and do this all over again. Let's write manually date to be z.courseDate, account ID will be zString, category ID will be Z.string, nullable and optional.
There we go. So this is our form schema here. So I believe that now the values seem to still not match, but okay, let's go ahead and let's just wrap things up here. So yeah, now what I wanna do is I wanna have actually two schemas here. So we're gonna have form values, but we're also gonna define type API form values.
And that's gonna be z.input, and that's gonna use type of API schema. And we're gonna create API schema just below form schema. So const API schema is going to be insert transaction schema. So the one we have from database schema, we can remove insert account schema here. And inside of here, we are just going to omit ID true.
There we go. So this way we have, Well, we are going to need this manually. I know it's a bit confusing because we didn't have to do this in the previous ones. Well, that's because these options are just so specific that it's easier for the types to have two schemas here. So now we have form values and we have API form values and we're going to do the following we're going to change the default values to use the form values but the onSubmit will use the API form values and I think that now there we go, onSubmit no longer has an error now we have these errors, we're going to resolve that next great so onDelete is fine, disabled is fine and now we have the account options which I want to be an array of objects label string and value string like that and then I'm going to copy and paste that and call this category options and then let's go ahead and create onCreateAccount to be a void which accepts a string Let's copy and paste that and call this onCreateCategory.
There we go and once I save this I believe we should no longer be having any errors inside of our new transaction sheet right here. So we are completely fine to just continue working in the transaction form itself. Let's continue here and let's add the account options, the category options, onCreateAccount and onCreateCategory right here. And now what we are going to do here is well, we are going to have to do some modification here obviously because of the type error but before we can start working here we have to install a component called React Select and then we have to create our reusable Select component and style it according to the existing styles. So let's go ahead and do the following.
Let's go inside of our terminal here and let's do bun add react select or npm install react select, depending on what you use right here. And now I'm gonna go ahead and close everything. So we have some errors here, that's fine. But let's go ahead and go inside of components for now and let's create our select.dsx component. So make sure you don't put it inside of UI because we're gonna have a separate select component which will be here.
That's gonna be the chat-cn one. But now we just want our own here so let's mark this as use client and let's import use memo from react let's import a single value from react select and let's import creatable select from react-select slash creatable like this let's define the props here so the props are gonna be onChange which will take in the optional value and return a void and onCreate will do the same thing but onCreate can be optional but the value is required when we are creating something if we are enabling that. Options itself are going to be optional and they are going to be an array of objects which are in format of label string and value string so exactly what we are formatting in our sheet and our form component. Value can be optional it can be string null or undefined and disabled is a boolean Placeholder is an optional string. So if you're wondering why did I put both the question mark and null and undefined, it's simply to satisfy the types, right?
Because I've already coded this project before and I know that the types are going to not work with just this but in this combination it works fine. Let's go ahead and let's export const select component here. And let's destructure from the props the value, the on change, let me scroll up so you can see, so value on change disabled, on create options and let's go ahead and ourselves define the default as an empty array and let's add a placeholder And I believe the errors will go away after we add an opening of the method. Inside of here, we're going to return the createable select component, which is a self-closing tag. And now let's create some methods here so on select we'll accept the option and the option is going to be the following so I'm going to collapse this like that so I can write the type in full line so it's gonna be the single value which we added an import for open pointy brackets and inside write label string value string and that is going to be our only prop which we accept and inside of here we're going to call on change to be option question mark dot value because it's optional right the single value itself can be null so we imported single value from react select so it matches our custom on select and then we can safely pass it here and let's go ahead and do const formatted value here to be use memo and let's return options dot find we find the option using the matching value.
There we go and inside of the dependency array of useMemo we add options and the value So that way we know which value is currently selected because we are going to pass the ID. So we have to find it in the array of options. And now inside of here, Let's go ahead and pass in all the necessary props like placeholder to be placeholder, last name, text small, height 10. So in this, I'm just matching the styles which are in the input component, right? So I think inside of here, you can find a height 10 and text small, right?
So I'm doing that here instead. And some styles we are gonna have to change like this. So React select has its own API for styling. So inside of here, we are going to get control, get the base, open and return an immediate object, spread the base, which basically means keep all existing styles except border color, which we are going to change to be e2e8f0 and on hover we're going to change the same thing so border color and just copy this again like this then we're gonna pass in the value to be formatted value and onChange is gonna be onSelect and options are going to be options. OnCreateOption will be onCreate.
My apologies, not onCreateOptions, but onCreate. OnCreateOption, individual and isDisabled is gonna be our disabled prop. So now what we've created is a generic reusable select component so because of this generic naming and props we can use this as a select component which will be able to list and use to create new categories, new accounts, whatever we want in the future, right? So it's very, very modular. That's what we wanted to achieve here.
Now we can head back inside of our, where is it? Inside of our features, transactions, components, transaction form. And now let's go step by step. So first of all, I'm going to log this and instead we're just gonna go ahead and log the values for now, because we're gonna have to do some modification with the values and you're gonna see why later. So let's start with accounts, right?
So let's go ahead and choose for the first field to be account ID here. And let's change this to be account. So the user is choosing the account and it's not gonna use input, is going to use our new select component from components select. So just make sure you've added an import for that I'm just gonna move it here we are gonna have input as well so don't remove it so we have the select here so let's go ahead and give it a placeholder of select an account Let's give it options to be account options. Let's give it on create to be on create account.
Value to be field.value. And let's give it on change to be field on change and disabled is going to be disabled like that, so I think that we can already see this in action I'm just going to refresh my localhost to ensure that the server has hot reload up to date So now let me go ahead and refresh one more time just in case. There we go. When I click add new, I have a select a new account and there we go. It loads cache.
And if I go ahead and type new account and press enter. You can see how the form is disabled and we just reused our hook which you can see immediately added the account here as well. So, yeah, okay, this is an accident, right? Because this data table is loading accounts. So ignore that, right?
Don't forget that we are loading accounts here because we copied and pasted from accounts. But as you can see that it's here as well. So now when I go here, you can see that I have new account. If I write test again, it's immediately added here and it's immediately added here. Perfect.
So that's what I wanted us to do with our nice reusable select component. Beautiful. And now let's go ahead and let's copy this form field entirely. Paste it just below this above this button here And this one is going to control the category ID. Right here.
So this will be choose a category and it's going to work in exactly the same way. So select a category. So category options on create category. And this I believe is exactly the same. So let's go ahead and check that out.
So I'm gonna refresh everything again. And now inside of here, there we go. I have food, but if I go ahead and select something new, there we go. It's created right here. And if I go into my categories it is right here created.
Beautiful! So you can see how powerful those hooks are because we can easily add them everywhere and we have the type safety so we are confident in our code and we know that we are handling this in a correct way. Beautiful! So now above these two fields I actually want to start with not the account or the category I want to start with choosing the date. So for that we're gonna have to create a component called DatePicker.
ChatCN does have a component called the DatePicker, but you cannot install it like any other components. So it's similar to our Form component. We need to use PopOver and Calendar to install it. So this is what we're going to do. We're going to add those two individually and then we're just going to build our own because ours is going to slightly be different from the ones they have in their example.
So let me go ahead and just go inside of my terminal here and do bannex chat CNUI latest, and let's add calendar. And besides the calendar, let's also add the popover component right here. So let me just confirm that I have everything I need here before I run my app. So inside of my package.json, I think that now I should have installed React-DayPicker. So I think that adding the calendar automatically installed that.
So just confirm your package.json that you now have a React day picker component here. Great. We now have the popover and the calendar and the React day picker. So let's go inside of components and let's create our date picker. TSX component.
Let's go ahead and import everything as react from react. Let's import format from date FNS, which we already have installed because we needed it previously. Let's import calendar from Lucid React, but let's do it calendar as calendar icon because we are also gonna have a component called calendar. And now let's import select single event handler from React day picker. Let's import CN from libutils.
Let's add our button component from add slash components UI button. And here we have the calendar component from dot slash UI calendar or components UI calendar. And lastly, we need to import all the things from our new pop-over. So that's going to be the pop-over, the pop-over content and the pop-over trigger component. There we go.
Now let's go ahead and let's define the type props here. So we're going to have value to be an optional type of date. On change is going to be select single event handler and disabled is going to be an optional boolean. Let's export const date picker. Let's go ahead and assign these props here and let's also destructure them so we're going to have value on change disabled.
Now inside of here, we're gonna go ahead and open the popover component. So this should be popover. Inside of here, we're gonna add the popover trigger component, which is going to have as a child property with a button component inside. We're going to give some attributes for this button, starting with the disabled to be disabled. Then we're going to have variant to be outline.
And then we're going to have a class name to use CN. In the default classes, it's going to have full width, justify, start, text left and font normal. And then dynamically, if there is no value, we're going to show text muted foreground to indicate to the user that date has not been selected. Then in here we're gonna use our calendar icon with the class name of size 4 and mr of 2. Let's just properly spell class name for jsx components and inside of here we're gonna check if we have value.
We're gonna use our format method. Otherwise, we're gonna return a span. Pick a date. In the format method, we're going to pass in the value in a format of PPP, like this. And then let's finally add the popover content.
And inside of here, let's add a calendar component which is a self-closing tab. So inside of here we're gonna give it a mode of single, we're gonna give it a selected of value, we're gonna give it on select to be on change And we're gonna give it disabled of disabled and initial focus. Like this. And I forgot to add return around here. So this would never actually render if we don't add that.
And there we go. That is our date picker component. We can now head back inside of our features, transactions, components, transaction form. And let's go ahead and let's import our date picker from components date picker here and I'm gonna go ahead and copy the form field here and I'm gonna paste it above so this is going to control the date so I'm gonna write... Well we don't have to say anything here so we can remove the form label entirely and in place of select we're gonna add our date picker component let's give it a value of field.value and let's give it onChange to be field.onChange and let's give it disabled to be disabled like that, there we go.
So let's ensure that we have our app running. For example, I don't. And let's try this out. So bun run dev or npm run dev, depending on your package manager or your run time. Let's wait a second for localhost to spin up and now if I go ahead and try and create a new transaction I have pick a date option.
There we go. Perfect. And when there is no selection, you can see how it's kind of transparent to indicate to the user that nothing has been selected. Great. So we have that and we have category ID and account ID.
Now let's add a simple one for the payee. So I'm going to go inside of my transaction form and I'm going to go ahead and copy the last one, category ID, and I'm just going to paste it below. So this one is going to control the payee field. So we're going to write payee here. And instead of select, we're going to have a good old input component.
So just ensure that you haven't accidentally removed the import for the input component here. Okay, let's just scroll here to the payee. Inside of here we're going to give it disabled. If it is disabled, we're going to give it a placeholder, add a payee, and we're going to pass in the field property. We're going to spread the field property.
So payee is just gonna be a plain text, right? Anything can be inside. Great, so what I wanna create next is Let's go actually with the simple one. Let's first add the text area here. So let's do Bonnex ChatCN UI latest add text area.
So this is another component that we need for our notes. So add this and now we don't have to modify anything here so we can just copy and paste the form field for the payee and this one will control the notes so let's write notes here instead of input this is going to be text area from components UI text area so just ensure that you've added this import right here and now what we are going to change is the following let's move the field to spread here so we overwrite everything after it So it's important the position of where you spread the field. So move it here and then add value to be field.value or empty string like this. And the placeholder is going to be optional notes. If you refresh your localhost, so every time you shut down your app, you have to refresh it again, even though you have localhost running, right?
Because the hot reload has been broken. All right, so let me click add new. And there we go. We have optional notes and we have payee. Perfect.
So what's missing is the amount component. So that's what we have to develop now. Let's start by adding a couple of packages required for the amount input component which is next. So first of all, let's do bun add or npm install react currency input field. If you want to, you can of course develop your own, right?
But this is a very good one. It has the perfect masking that I want and I can easily make it look like a chat CNUI component so it works perfectly fine for me and then let's do bun X chat CNUI at latest and let's add a tooltip component here so that we can indicate to the user some useful actions and let's do bun run dev So I'm gonna go ahead and close everything and go inside of my components and create a new amount input.tsx. Let's go ahead and let's import the currency input from react currency input field. Let's import all the icons we are going to need from Lucid React. So those are going to be the info, the minus circle, and the plus circle components.
Let's prepare our CN and now let's add from components UI tooltip everything we are going to need. So we're going to have a tooltip component itself, the content, the provider and the trigger component. Let's define the props here. So value will be string, onChange will be value, string or undefined and a void and placeholder will be a string optional and disabled will be an optional boolean. So why am I using string as the value here?
Well that's because this react currency input doesn't just mask things it also handles the decimal the well what's the correct term for this the numeric value right we remember that problem we talked about that JavaScript works with floats so we don't have that precision. Well in here they handle that right and in JavaScript that doesn't exist in any other way than a string right so that's why we have to work with strings here. So let's go ahead and let's just quickly define this component So const amount input. Let's go ahead and attach the props here. Value on change placeholder and disabled.
And now inside of here, all I wanna do for now is just return a div hello. The reason I wanna do that is because I want us to go back inside of the transaction form component features and the render it so that we can see it here and so that we can see what we are developing. So let's go inside of the transaction form and let's go ahead and add our new amount input component from components amount input here. Right here and I want us to go and copy the payee and paste it just above notes. So next to last.
So this is going to be the amount field. So let's go ahead and let's write amount here instead of input. It's going to use the amount input. And for now, what we're going to do is we can spread the fields like this and we can make the placeholder be 0.00 like this. I'm going to refresh my localhost here because I've shut down the server and all I want to do is I want to see that component so for now all that should appear is a text which will say amount input I believe.
Hello, yes there we go so we have the amount label and we have hello as text perfect, so that is enough for us to start developing this so first of all, let's go ahead and let's do the following let's go ahead and let's parse the value so parsed value will be parseFloat value but we are only going to use it for this to detect whether something is income. So if parsedValue is larger than zero, or if something is an expense. So parsed value is less than zero. So that's why we are using parse float here, just so we can do these comparisons. Great.
And now I wanna do the following. I wanna define a method const on reverse value. So our users can easily change something from being an expense into an income or vice versa. So usually they would have to manually write the minus and they can still do that, but I want to give them a useful little button for that. So First of all, if value was not entered, no point in even doing the math here.
Otherwise, we're gonna do an onChange here and we're gonna pass in open parentheses, parseFloat value times minus one to string. Like that. Or you can do const reversed new value. You can do that for example, and then just do this. And then just do this.
And then do new value to string. Perhaps is, whoops, perhaps this is clearer. There we go. And now let's go ahead and let's start developing this. So first of all, we're gonna have a div, but the div is gonna just have a relative class name so we can position elements inside.
And then let's add a tooltip provider here, like that. And let's go ahead and give it a tooltip child. Let's give it a delay duration here of 100. So it opens a bit quicker. Let's add a tool tip trigger component.
So let's give it an as child option because inside is gonna use a native HTML button element. This will have a type of button. On click here will be a very simple onReverse value which we've just created so the user can easily change something from an income to an expense and now let's go ahead and give it some class names here so class name is going to be our usableCN by default it's going to have BG slate 400 onHover BG will be slate 500 It's going to have an absolute position. So that we can position it how we want. So top will be 1.5, left will be 1.5.
You're gonna see why this will make sense when we add the input component right so let's add rounded medium padding of 2 so there we go you can already see the little button right here but it doesn't have anything inside so padding off to flex items center and justify center and transition and then inside of here we're gonna do the following If there is no parsed value at all, in that case, we're gonna add an info like this and we're gonna give it a class name of size three and besides size three, it's gonna have a text white. Let's copy this two times. For the second one we're gonna use plus circle and for the last one we're gonna use minus circle. So this one will not just check if there is no parsed value, instead it's going to check if is income. And the last one will check if is expense.
Like that. Perfect. So there we go. Now we have an info component here and now outside of the trigger we add a pull tip content which will simply say use and I'm gonna specify plus like this for income and minus for expenses like this. So there we go now when the user hovers they know to use plus for income or minus for expenses or they can simply click here.
You're gonna see how intuitive it is later. Let's go outside of the tooltip provider and let's add our currency input component right here. And now what we have to do is we have to style it. So you can see it's right here but we have to style it a bit so let's go ahead and do the following let's give it a prefix of a dollar sign we can change this later right but let's keep it dollars for now and now we're gonna have gonna have to write a pretty big class name here which is going to just basically match our input field. So what we can do is we can go inside of UI, Components UI, Input.
So if you don't want to write it out you can just copy the entire thing from here. So just these default class names here and just paste all of that here. Like that. There we go. So you can see how now it looks exactly as our input above but we have a little problem here.
So what we're going to add in this currency input before everything is a very simple padding left of 10 so we leave space for this. There we go. Perfect! So now we have the class name. Now let's add a placeholder here to be our placeholder.
Let's go ahead and give it a value of value. Let's give it a decimal limit of 2. And let's give it a decimal scale of 2 as well. So I always want to work with two decimals. On value change here is going to be on change and disabled is going to be disabled.
And just below that I'm going to add one more thing, just a very simple paragraph which will check if isIncome. In that case it's going to say this will count as income. Otherwise, if is expense, it will say this will count as an expense. And we're going to give this a class name. Text extra small and text muted foreground and margin top of 2.
Like that. Let's go ahead and try out our new component now. So there we go. This will count as income. But if I add a minus, this will count as an expense.
And I can switch it from here as you can see. Well let's go ahead and add some color indication just so it looks a little bit better. So instead of this button here we define class name with the initial values and now Let's add if is income We're gonna add BG Emerald 500 And let's go ahead and do the following. Let's add We can copy this and we can add on hover BG Emerald 600 Copy and paste this and let's do is income. Instead of emerald we're gonna use a rose like this.
There we go. So now this will count as income. Actually let's reverse the values. I think I did it incorrectly. This is expense.
Yes, my apologies. There we go. So this will count as income. But if I click here, it says this will count as an expense. Perfect.
So user can either write like this and then they can add their own minus or they can always switch from here and it will and they if they have any doubts right here we have a little tip for them how this will count so they know exactly what's going on. Perfect! So I believe our transaction form is now ready to be submitted. So let's go ahead and try this out. Let's just confirm inside of the new transaction sheet right here that we are actually using the create mutation.
It looks like we are. I think that there's nothing else we have to do here. So this is how we're going to try it out. So I'm gonna go ahead and open my API transactions here. There we go.
So local host 3000 API transactions and inside of here I'm gonna go ahead and try and create a new one. So I'm gonna pick a date, 9th of May. I'm gonna choose the cash account, the food category or whatever you want. The payee is gonna be payee. And I'm gonna choose an amount of 500.
And I'm gonna write test here. And I'm gonna click create an account and let's see Looks like something is wrong here. So we're gonna have to debug Well, oh we are not submitting anything. Yes. So, okay.
These are the values here account ID amount Category the date great. So this is fine, but I forgot we have to do one change before the submit it's about the amount field. So if you remember we made a decision on how we are going to store our amounts. And we ended up on this, using integers of the smallest unit of the currency, or in our case, we're gonna use milli units, which means we have to convert this to milli units. So this is an example of 10 and 15 cents.
In our case, we have $500, right? So we're gonna have to modify this using, well, we're gonna create our own little reusable lib for that, so we can use it everywhere where we need to. And the reason I want to do this on the front end is, well, I looked at the API specifications of existing applications which do this and their API, and they do the same thing. And also because it's a good argument that it's the same way we parse dates, right? So we don't modify how the date is being sent on the backend.
It just expects a specific format. And it returns it in a specific format as well, which is the ISO string. And then the frontend has to take care of making it look good. So it makes sense to use the same logic for our custom amount situation here. So what we're going to do is we're gonna go ahead and we're gonna create a method called convert amount to milli units.
So let's go inside of our lib folder, inside of the utils here and let me just go ahead and order these how I like it so let's export function here convert amount function, convert amount to milli units It's going to accept an amount which has to be a number and it's going to simply return math.round amount times a thousand like that. Let's also create the equivalent opposite which will be convert amount from milli units which will very simply get the amount and divide it by a thousand. So we're going to use... Oops, let me just close this. So we're going to use this to create the amount we can store in the database.
And we're gonna use this to show that amount to the user, right, because user doesn't care about milli units. User needs to see that in dollars or cents or euros or whatever your currency is, right? So now that we have that, we can head back inside of our features, transactions, components, new transaction form, and we can head back inside of our handle submit method here. So what we're going to do is we're going to get const amount in milli units. Convert amount to milli units and pass in let's go ahead and define our amount to be parseFloatValues.amount and pass in the amount like this so just confirm you have imported the convert amount to milli units here there we go We have this and now we can safely submit that in here by doing the following, spread the values and pass in amount as amount in milli units.
And there we go. We now have no type errors inside of here. Perfect. Yes, I think yeah, the reason we needed the custom form schema was because of the amount. We needed to keep it as string here, right?
That's the important thing. Great. Let's go ahead and try this out again now. So I'm gonna go ahead and let's use our specific situation which was it 10 15. Let's say that's our income 10 15 here or maybe it will make more sense to this to be an expense and let's click create an account.
Oh it still says create account so we have to change that. Okay, let's refresh this and there we go. And you can see exactly how it's stored, exactly how we want it. So we have the ID, we have the date, so 8th of May, food category ID. So everything is here exactly as we expected it to be.
Perfect. So before we wrap up the chapter let's just fix this button do not say create account but instead let's make it say create transaction right here and delete the transaction. We're gonna see this later in the next chapter when we enable editing of individual transactions. So we just created a bunch of new components so feel free to take a look in my GitHub source code if you are unsure and see you in the next chapter.