[0:00] in this video we're going to build fully [0:01] functional software as a service project [0:04] with Lal 11 react Talon CSS and stripe [0:08] online payments on registration user [0:10] gets 10 credits by default there are two [0:14] features implemented in the project the [0:16] first one is to calculate sum of two [0:18] numbers which requires one credits and [0:20] the second feature is to calculate the [0:22] difference of two numbers which requires [0:24] three credits these are simplest [0:27] possible features which I implemented [0:29] for Simplicity my main focus in this [0:31] project is to build software as a [0:33] service website in reality these [0:35] features might be as complex as [0:37] generating script of the uploaded audio [0:39] file restoring broken images using AI or [0:42] generating 3D avatars based on uploaded [0:46] portrait images the number of credits [0:48] required for a specific feature is also [0:51] customizable I have also defined three [0:53] packages to purchase credits these are [0:55] coming from the database so the number [0:57] of credits inside package or the price [1:00] of package is also customizable once the [1:02] user doesn't have enough credits to use [1:04] a specific feature they can choose the [1:06] package they want pay using stripe [1:08] online payments after which the blocked [1:11] feature will become activated again and [1:13] user will be able to use it on dashboard [1:15] you're going to see all your used [1:17] features you're going to see the feature [1:19] name how many credits you spend on that [1:21] feature at what time you did that and [1:24] additional information that might be the [1:27] input you gave to that specific feature [1:29] out output the feature generated and any [1:32] other information you want to put right [1:34] here the link of the project source code [1:37] will be in the video description I'm [1:39] super excited to hear your opinion on [1:41] this project so let me know your [1:42] thoughts in the comment section down [1:44] below repairing building and editing [1:46] such type of projects requires a lot of [1:49] time and energy 70% of the channel [1:52] viewers are not even subscribed to the [1:53] channel if the project idea excites you [1:56] the single best thing what you can do [1:58] right now is to hit the Subscribe button [2:00] and enable notifications additionally [2:02] liking the video and providing a [2:04] positive comment will help the channel a [2:07] lot to grow all right no further Ado [2:10] let's start building this awesome [2:11] project before we start working on the [2:13] project let's just make sure that we [2:15] have all the necessary programs [2:17] installed if I don't develop my projects [2:19] with Docker I generally use examp so if [2:22] you don't have PHP comment globally [2:24] available in your terminal I recommend [2:26] to download and install examp if you [2:29] already have PHP available you don't [2:31] need to do anything so we're going to [2:33] need composer which is the PHP package [2:34] manager we're going to need node.js as [2:36] well because we're going to create the [2:38] reactjs application as well as a choice [2:40] of the IDE editor I'm going to use [2:43] Visual Studio code for this particular [2:45] tutorial I use generally PHP storm or [2:48] Visual Studio code for PHP I prefer to [2:50] use PHP storm however for YouTube and [2:53] for such type of tutorials I'm trying to [2:56] use more Visual Studio code because I [2:58] can understand that most of you doesn't [3:00] have that uh cannot afford PHP storms [3:03] paid license that's why I try marking my [3:06] working setup to be as close to your [3:09] working setup as possible that's why I [3:12] have I'm going to use vs code and um [3:15] with a couple of extensions I have also [3:17] a dedicated video how to set up vs code [3:19] for Lal development you can check it out [3:21] on my YouTube channel okay and I'm going [3:23] to use gitbash if you don't have gitbash [3:25] uh it comes with a git just download and [3:27] have it I recommend to use gitbash [3:29] because that's my preferred terminal on [3:31] Windows on Mac or or on Linux you can [3:34] use your preferred terminal that's [3:36] absolutely fine gitbash is not something [3:38] like a must have okay now I'm going to [3:41] open gitbash and I'm going to create a [3:43] LEL project by executing composer create [3:47] d project laravel SL laravel in here I'm [3:53] going to provide the local folder name [3:55] Lal 11- react D SAS and I'm going to hit [4:00] the enter which is going to download the [4:02] LEL project and set it up for [4:05] us in this tutorial we're going to learn [4:07] how to build software as a service [4:09] project with Lal and react however if [4:13] you want to deploy this specific project [4:15] on production environment and assign [4:18] custom domain to it I do have separate [4:20] dedicated videos on specifically [4:22] deployment my personal choice of Hosting [4:24] provider is hostinger which is very [4:27] kindly sponsoring this video let's see [4:29] how lot of installation goes okay it is [4:31] downloading packages and progressing I [4:34] have been personally using hostinger for [4:36] past three years and I have been [4:38] extremely happy with their services they [4:40] provide shared hosting VPS hosting Cloud [4:43] hosting and even email hosting their [4:46] prices are very affordable and servers [4:48] are very fast let's check Lal [4:51] installation progress okay it finished [4:53] installation and now we're going to open [4:55] it using vs code now I'm going to bring [4:58] up the terminal and and collapse the [5:00] left side and I'm going to install Lal [5:02] Bree composer require [5:06] l/ Breeze D- Dev once Breeze is [5:11] installed we're going to execute PHP [5:13] Artisan Breeze colon install it's going [5:16] to ask us which stack we would like to [5:18] install and I'm going to go with react [5:21] then it's going to ask us which [5:22] additional features we want to include [5:24] and I'm going to choose dark mode and [5:26] the final question is which testing [5:28] framework we want we prefer and I'm [5:31] going to leave this default because I'm [5:32] not going to write test in this project [5:34] I'm going to hit the enter and it's [5:35] going to require additional packages [5:38] like inertia related packages uh [5:41] additional uh react related packages [5:44] Ziggy and it's going to set up the react [5:47] within nura project for us hostinger [5:50] shared hosting services start at [5:53] $2.99 per month during holidays this [5:56] price goes even lower and that price [6:00] includes free domain free unlimited [6:02] number of SSL certificates unlimited [6:05] number of databases G support SSH access [6:09] backups and even more I recommend to [6:12] check their website explore your desired [6:14] service check all the features because [6:16] there are tons of features actually [6:18] included in this price and if you decide [6:20] to grab the hosting during checkout use [6:23] the coupon code zura TC which will give [6:26] you extra 10% off on already discounted [6:29] price all the links will be in the video [6:32] description and I want to say big thanks [6:34] to hostinger for supporting this channel [6:36] so far and sponsoring this video the [6:39] command also executed mpm install and [6:42] bued also react assets and we can start [6:45] the Artisan server already by executing [6:48] PHP Artisan serve and I'm going to open [6:51] second terminal and I'm going to execute [6:53] mpm run Dev to have the V server up and [6:57] running for development purposes now [6:59] let's open the browser and I'm going to [7:01] type Local Host Port 8000 and we're [7:03] going to see Lal 11's default welcome [7:07] page this is awesome now let me enable [7:09] dark mode for this I'm going to open tnd [7:13] config JS and I'm going to add right [7:16] here uh dark mode property to be based [7:21] on class and I'm going to also open up [7:25] dot. blade PHP which is the main layout [7:28] file in and I'm going to add right here [7:31] class to be dark as soon as I save this [7:33] and open in the browser we're going to [7:35] see that LEL 11's welcome page is [7:38] already in the dark mode all the [7:40] migrations are also properly applied so [7:42] if I try to register right now I was [7:46] able to successfully register and I'm [7:48] also authenticated now let's generate [7:50] models and migrations PHP artisan make [7:55] model package is the first model with [7:57] migration I'm going to also [8:01] generate transaction [8:07] model then we're going to generate [8:11] feature [8:12] model and I'm going to also [8:15] generate used feature [8:19] model okay we have four models and four [8:22] migration files let's close this and I'm [8:25] going to go inside database migrations [8:28] and I'm going to open all four migration [8:32] files and I'm going to work on each of [8:35] them one after after another okay let's [8:39] write the migrations and in the packages [8:41] table we're going to need the name of [8:43] the package like basic silver gold and [8:46] so on we're going to also need the price [8:48] for each package and the number of [8:50] credits inside each package then let's [8:53] go into transactions here we need the [8:55] status of the transaction so whenever we [8:57] create the transaction and whenever we [8:59] redirect user to the stripe checkout [9:01] page the transaction status will be [9:03] pending then whenever the uh payment is [9:06] completed the transaction status is [9:08] complet is changed into done or paid and [9:11] then we're going to also increase the [9:14] number of remaining credits for the user [9:17] okay so we will need the status on [9:19] transaction we're going to need also the [9:22] price for each transaction we need how [9:24] many credits that transaction included [9:26] the session ID and this is going to be [9:28] the stripe checkout session ID we're [9:31] going to need the user ID who made that [9:33] transaction and we need package ID and [9:37] uh I think that's it yeah we don't need [9:39] anything else then we are going to [9:41] create the features table here we need [9:44] the image we need rout name that's going [9:47] to be the actual rout name okay we're [9:50] going to need the name description [9:52] required credits and the active flag [9:55] whether this feature is active or not we [9:58] can have multiple features but you can [9:59] easily deactivate them from the database [10:01] and they will not be um just displayed [10:04] on the website and users will not be [10:06] able to use that specific features also [10:10] then we go into used features and here [10:13] we will need credits we will need [10:15] feature ID we will need user ID we will [10:18] need um data which is going to be [10:21] additional information when the user [10:25] used the specific feature what [10:27] additional information the user passed [10:30] to that feature [10:32] okay so this is great so we created four [10:35] tables um for migration files let me [10:38] close all of them and I'm going to open [10:40] now models like I'm going to open [10:43] hackage PHP I'm going to open [10:46] transaction PHP I'm going to open [10:50] feature oops feature. PHP and I'm going [10:55] to open used feature. PHP [11:00] let's start with the package PHP and [11:02] we're going to first provide um elements [11:05] inside the fillable so we're going to [11:07] need name price and credits inside the [11:10] fillable then let's go in transactions [11:13] and here we need fillable as well [11:15] providing status price credits session [11:18] ID user ID package ID and I think that's [11:21] it and I'm going to also Define relation [11:23] from transaction to user uh and the [11:27] transaction belongs to user we're going [11:28] to need that [11:29] relation uh then let's go into feature [11:32] and here we need image Road name we need [11:35] name as well we need description [11:38] required credits and active as well okay [11:42] and in the used features we need a [11:43] couple of more information um except [11:46] that like other than fillable uh we need [11:49] feature ID user ID credits uh we also [11:52] need the casts basically we have the [11:55] data property in the used features which [11:57] is Json B [12:00] uh and we're going to convert that into [12:03] an array basically or whenever there's [12:06] an array we're going to save this as a [12:08] Json in the database because we are [12:10] using SQ light we need that cast so [12:13] we're going to return that the data is [12:15] basically an array uh this is additional [12:18] uh like a new feature in Lal 11 [12:21] previously cast uh casts in Lal 10 was [12:24] an array but now in Lal 11 we can have [12:27] costs as a function [12:30] okay then down below we need the [12:32] relation from the use features to user [12:34] where the use feature belongs to user [12:37] and down below in the same way we need [12:39] the relation to feature [12:41] itself now we have all the modules and [12:44] migrations ready I'm going to close [12:46] everything and I'm going to open [12:48] database Cedar and right here I'm going [12:51] to update the existing user Factory let [12:53] me actually delete everything and [12:56] rewrite okay first let's create the US [12:59] user and we're going to provide name [13:00] email and encrypted password to the user [13:03] then we're going to create U several [13:05] features so um this is a dummy image [13:09] which I actually grabbed from the Google [13:11] this is just a plus image so I can click [13:13] right here it actually opens into [13:16] another tab let me open this very [13:18] quickly right here this is a plus icon [13:21] okay so because we're going to implement [13:23] very dummy features like just to [13:26] calculate the sum of two numbers and [13:27] difference of two numbers we're going to [13:29] just have an image for the feature okay [13:32] then we're going to need the root name [13:35] okay and the root name in this case is [13:37] feature one. index why I use this [13:39] feature one right here and uh the name [13:42] used as a calculate sum for example [13:45] because I don't want to stick just with [13:47] my features my features are Dam features [13:49] as I mentioned they are called calculate [13:51] sum and calculate difference but I also [13:54] uh use the names like feature one [13:56] because uh those are very generic [13:59] features and the whole idea of this [14:00] project is that you can Implement your [14:03] own additional features uh you can take [14:06] this project remove those dummy features [14:08] Implement your own features and you're [14:10] going to have something awesome okay so [14:13] sometimes I use calculate some sometimes [14:14] feature one so don't uh get confused [14:17] with that okay so then we in the [14:20] description we have calculate some of [14:21] two numbers we have number of required [14:24] credits for this Feature Feature one [14:26] basically and we have the active as as [14:29] well so then down below I'm going to [14:31] just uh paste this entire feature two [14:34] which has the road name feature two the [14:37] image is for the minus calculate [14:40] difference the description this requires [14:43] three credits okay each one requires one [14:46] credit this requires three credit and we [14:49] have the active true so uh and down [14:52] below we're going to Define packages as [14:53] well each package will have a name we [14:56] have price and we have number of credits [15:00] and I'm going to just duplicate this and [15:03] have silver with price 20 credits 100 [15:07] and duplicate this once again and we're [15:09] going to have name golden price 50 and [15:11] credits 500 and just like this we have [15:14] this uh migration um sorry the database [15:17] C ready we just need to import the [15:19] package up modules package and the [15:22] feature because we are using this um [15:24] right [15:26] here okay we added new column in the [15:29] users and this is called available [15:31] credits we added migration for this [15:33] whenever the new user is created we want [15:36] the available credits to be set as 10 [15:39] for every new user so we're giving every [15:42] user 10 credits upon registration okay [15:46] how we're going to do this I'm going to [15:47] create user Observer for this let me [15:50] open the terminal and I'm going to [15:51] execute PHP artisan [15:55] make Observer user [15:59] Observer let's hit the enter it created [16:02] that user Observer we're going to open [16:04] this it doesn't open [16:08] user Observer and we are going to add [16:12] right here public function creating okay [16:15] which accepts instance of the user and [16:18] we can import that user um app models [16:22] user inside this class and what we need [16:24] to do is just to set [16:27] user available [16:30] able [16:33] credits equals 10 so whenever the new [16:37] user is created we're going to set this [16:39] available credits to 10 and we just need [16:42] to now use that user Observer and [16:45] slightly new method of using the [16:47] observers on models is the is using uh [16:52] PHP attributes so here we're going to [16:55] use attribute called uh obser oberved [17:00] Pi oops what just happened observed [17:04] Pi this one and we're going to provide [17:07] the class name which should observe the [17:10] current model so in our case this is [17:12] going to be user [17:15] Observer okay through this line I'm [17:18] telling LEL that this class is observed [17:22] by user Observer so whenever the new [17:24] instance is created for this user it's [17:26] going to call this creating function [17:28] passate user and the 10 will be set now [17:32] what we need to do is just bring up the [17:34] terminal again and execute PHP [17:38] Artisan uh migrate so if I execute [17:40] migrate it's going to apply new [17:42] migrations the new migrations are those [17:45] four migrations we just created but we [17:47] also change something in the user [17:49] migration and plus we want to execute [17:51] seed data as well so I'm just going to [17:54] execute PHP Artisan [17:57] migrate um [17:59] bres Das D seed it's going to drop [18:03] everything reapply everything and it's [18:04] going to seed the data as well now I [18:06] want to check what is the data uh inside [18:09] the database so I'm going to access the [18:11] database through Tinker PHP Artisan [18:16] Tinker okay let's um let's get the first [18:19] user user first and this is the first [18:23] user it has all that information what [18:26] what we provided in the database CER and [18:28] it also has this available credits 10 [18:31] awesome uh now let's execute up [18:37] models feature and get all features here [18:41] and we see two features basically with [18:44] their all the information and you can [18:46] assume that in the same way credits um [18:49] uh sorry packages we also are also [18:52] created so I'm just going to just uh [18:54] select them as well but we have the [18:56] database structure ready and we o have [18:59] the SE data [19:00] ready now let's bring up new terminal so [19:03] this terminal is actually for Tinker [19:05] this is for V this is for Artisan I'm [19:07] going to open one more terminal this is [19:09] going to be my Artisan terminal and I'm [19:11] going to create new controller feature [19:13] One controller PHP artisan make [19:18] controller feature One controller and in [19:22] the same way let's just create feature 2 [19:26] controller as well okay awesome so let [19:29] me close everything and now I'm going to [19:31] open feature One controller and I'm [19:35] going to work right here first of all [19:38] I'm going to Define public um feature [19:41] class uh instance basically property uh [19:44] which will be nullable and by default [19:46] I'm going to assign this um null okay [19:48] I'm going to Define also Constructor I'm [19:51] going to Define index function and I'm [19:53] going to Define calculate function and [19:54] I'm going to explain why I have those [19:56] functions before I write anything okay [20:00] so inside the Constructor I'm going to [20:01] select the feature based on the root [20:04] name and I'm going to save this in this [20:06] public feature property okay inside the [20:09] index I'm going to render the feature [20:12] page and inside calculate I'm going to [20:14] handle the post submission of the [20:17] feature I'm going to do all the [20:19] operations that is necessary for that [20:21] specific feature and I'm going to return [20:24] the result render the result or redirect [20:27] back to the index with the result okay [20:32] and this controller is kind of universal [20:34] controller feature One controller you [20:36] can create similar controllers for your [20:38] specific features whether this is going [20:40] to be speech to text or image [20:43] restoration or um image generation [20:46] whatever okay you will render uh the [20:50] form for example upload image F image [20:52] file then you're going to handle this [20:54] inside the calculate you can call this [20:57] method whatever you want and then you [20:59] will redirect user back to index with [21:01] the actual result of the calculation [21:04] okay this is awesome now inside um [21:07] Constructor let's select this feature [21:09] based on the road name where the road [21:12] name equals feature one. index okay if [21:15] you if you remember in the database s [21:18] this is the root name what we gave to [21:20] the feature one I'm going to also uh [21:23] select if the feature is active if the [21:26] feature is not active simply I want to [21:29] show [21:30] 404 so if for some reason I decided to [21:34] deactivate the feature I don't want the [21:36] users to use that specific feature I [21:39] will change its active status and nobody [21:41] be will be able to use [21:43] that okay once I have the feature [21:45] selected then let's move into index here [21:48] I'm going to render the inertia page [21:51] okay however I am going to pass the [21:55] feature right here so uh first of all [21:58] just pay attention that this feature one [22:00] index doesn't exist okay so we're going [22:02] to create that function and not a [22:05] function it's going to be a reactjs [22:07] component okay and we're going to pass [22:10] the feature which is going to be a [22:12] feature resource this is another [22:15] thing the feature resource is another [22:18] file that doesn't exist okay and we're [22:21] going to pass to that feature resource [22:23] this feature we're going to create that [22:25] feature resource in a moment okay and [22:28] I'm going to pass additional property [22:30] which is going to be the answer okay [22:33] whenever we calculate the answer from [22:34] this calculate function we're going to [22:37] put this in the session redirect user [22:40] back to the index and we're going to get [22:42] that from the session and pass it as the [22:45] answer variable inside this feature one [22:47] index now we're going to do two things [22:50] uh first we're going to create this [22:51] feature resource so I'm going to [22:53] basically bring up the terminal and [22:56] execute PHP design make resource feature [23:03] resource let's hit the enter feature [23:05] resource was created let's open that and [23:09] I'm going to change this return an array [23:12] and I'm going to define the properties [23:13] right [23:14] here we're going to return ID we're [23:17] going to return image Road name name [23:21] description required credits and active [23:25] Okay so why do I need this Source you [23:29] probably have a question I'm returning [23:31] almost every property except created [23:33] that and updated that generally the [23:36] inertia type of applications where you [23:39] use react or view it doesn't matter the [23:42] information what you pass to that react [23:45] component in this case feature will be [23:47] visible inside the browser so if you [23:50] pass sensitive information as a variable [23:53] to that feature one Index this is no [23:56] good okay that information will be be [23:58] can be um exposed to um anybody else [24:03] basically so we want always to give the [24:06] models to the resources and return that [24:10] resource to the uh give that resource to [24:14] the [24:15] component okay so this is a security [24:17] measurement um and it's a very [24:19] recommended thing actually to do so we [24:23] now have this feature resource and what [24:26] we need to do um with we obviously need [24:29] to import the feature resource but let [24:30] me actually uh continue and then I will [24:32] import that [24:36] okay then I'm going to inside calculate [24:39] I'm going to get the user okay and I'm [24:41] going to do the following check if the [24:43] user's available credits is less than [24:47] the number of credits the feature [24:50] requires it means that we don't user [24:52] doesn't have enough credits so we simply [24:54] go back we don't proceed with the [24:56] calculate so if it's enough then we [24:59] start validation of the data so we're [25:01] going to validate the number one uh [25:04] basically uh the we're going to [25:06] calculate some of two numbers right so [25:08] we're going to have number one and [25:09] number two and we're going to get those [25:11] two numbers I'm going to create separate [25:14] variables out of that and cast them into [25:16] float variables and then I'm going to [25:18] calculate the sum of those numbers but [25:21] I'm going to also save in the database [25:23] that user used the feature okay I'm [25:26] going to also decrease the number of [25:28] credits on the user so on the user I'm [25:32] going to call this decrease credits and [25:34] I'm going to pass these feature required [25:37] credits so if the feature requires one [25:39] credit we're going to decrease the users [25:41] available credits with one if the [25:43] feature requires three credits we're [25:45] going to decrease it by three okay once [25:48] we do this then we're going to save used [25:50] feature we're going to pass the feature [25:52] ID we're going to pass the user ID we're [25:55] going to pass the credits and we're [25:57] going to pass additional data so this [26:00] user used that feature which cost that [26:03] amount of credits and this is the [26:04] additional information which contains [26:06] number one and number two again this is [26:08] kind of something Universal which I [26:10] wanted to create for uh almost all kind [26:13] of features so even if you do like a [26:15] image conversion or um like speech to [26:18] text whatever you have the feature ID [26:21] user ID number of credits and inside [26:23] this data you can put any additional [26:25] information you want you can put uh like [26:28] image one image two and whatever okay [26:32] once we save that used uh feature uh [26:35] then we simply go to uh rout feature [26:37] one. index we redirect user back to the [26:41] index page and we're going to pass also [26:43] the answer the answer will be number one [26:46] plus number two and this is going to be [26:49] it okay so I'm going to scroll up and [26:51] I'm going to include that feature [26:53] resource I'm going to include the uh [26:55] models feature and I think we need the [26:59] used feature as well okay now we have [27:02] this feature One controller ready um I [27:04] can close that and I'm going to open [27:07] actually I need to do one additional [27:09] thing in the feature resource I am going [27:11] to create right [27:13] here public [27:16] static um WP equals false so I'm [27:21] disabling W for this feature resource [27:25] okay I'm going to close this now let's [27:26] open web.php [27:28] and let me scroll down below and I'm [27:30] going to create Define the rules for the [27:32] feature one now let's create feature one [27:34] component feature one index component [27:37] I'm going to go into resources JS pages [27:41] and inside Pages I'm going to create new [27:43] file called feature one slash index that [27:48] should be uppercase i index js6 let's [27:52] hit the enter so here we have this index [27:54] js6 and I'm going to also create one [27:56] component under component section so [27:58] that components basically is um was [28:02] added by Lal breeze so here we have [28:05] couple of ready components which we are [28:06] going to use but I'm going to add one [28:08] more component and this is going to be [28:10] feature JS jsx component so I'm going to [28:13] create one reusable feature js6 [28:16] component which I'm going to use in [28:19] feature one component and feature two [28:21] component as well and you can use in any [28:23] other components um you are going to add [28:26] in any other feature components you are [28:28] going to add so that's going to be a [28:30] generic feature component which will [28:32] display the feature name feature [28:34] description number of credits required [28:36] for the specific feature and this will [28:38] be also responsible to lock that [28:42] specific feature if the user has a less [28:44] number of credits than the feature [28:47] requires okay so this is good so I'm [28:49] going to collapse the left side and [28:51] let's implement this feature [28:53] component let's define now component [28:56] export default function feature and I'm [28:59] going to also import the necessary um [29:02] classes like we're going to use [29:03] authenticated layout which is the main [29:06] layout what we see when we access the [29:09] dashboard page right now I'm not [29:11] authenticated but when you authenticate [29:13] you see the dashboard with the nav bar [29:15] this is the authenticated layout okay [29:18] and that authenticated layout also is [29:20] used in dashboard js6 and we're going to [29:23] use it in the same way then I'm going to [29:26] import couple of classes components from [29:29] inera Jes react package so we're going [29:33] to need the head link and use page and [29:36] I'm going to explain uh what each does [29:39] whenever I'm going to use that okay [29:42] inside feature we're going to get these [29:44] um properties like feature answer and [29:47] we're going to get additional children [29:49] then I'm going to use page from this [29:52] injs react and that gives me the page [29:55] object which has props okay and from [29:58] that page props I'm going to get the out [30:01] that out contains the user inside okay [30:05] so I can access out. user and the user [30:08] has available credits and I will get [30:11] this available credits inside in on its [30:14] own separate variable but how do I know [30:17] that this page props has out I'm going [30:20] to open uh handle inertia JS requests [30:23] middle we which comes with this U [30:26] inertia Js basically and right here if [30:29] we scroll down below inside sheare [30:31] function which uh the shear function [30:34] basically are those variables uh it [30:37] returns an associative array where keys [30:39] are those variables which are shared [30:42] across all pages of inertia JS react or [30:46] view doesn't matter so in this case we [30:48] are returning out so that out property [30:51] will be available on every react [30:54] component page okay and once [30:58] uh we are going to have that uh feature [31:01] one component rendered right here which [31:03] is going to be Associated to uh Road [31:06] this is going to be rendered from the um [31:08] controller feature One [31:11] controller the the out will be available [31:14] in every component basically it doesn't [31:15] matter you can access this out in the [31:17] index JS feature one index JS or feature [31:21] js6 uh yeah the out will be always there [31:25] and through that we get this authent the [31:27] avail aable credits okay let's move on [31:29] and I'm going to return the uh jsx um [31:33] from here I'm going to use this [31:34] authenticated layout pass the user and [31:37] header to this authenticated layout [31:39] similar to how it is done in dashboard [31:42] inside header I'm going to pass this H2 [31:44] and I'm going to provide the feature [31:46] name as a title okay the feature is [31:49] accepted right here then if I scroll [31:51] down below I'm going to use this head [31:53] and that head basically is the HTML head [31:57] tag [31:58] okay and the title is the HTML title tag [32:02] and this comes from again inertial JS [32:05] react and it's going to handle this [32:07] using the title properly in the head [32:10] section okay the title in this case is [32:12] feature one you can call this feature. [32:14] name if you want then down below I'm [32:16] going to create couple of Dives with the [32:18] Talan CSS classes to properly uh set up [32:22] the layout car type of [32:24] layout and we're going to also output [32:27] the answer right here at the top of the [32:30] four so if the answer is not [32:33] null and then in this case we're going [32:36] to render this Steve okay which will [32:39] have like a green background text white [32:42] and inside there I'm going to Output [32:44] result of calculation is the answer that [32:47] answer is received right here okay then [32:50] we're going to proceed we're going to [32:51] create one additional [32:53] div and inside there I'm going to check [32:56] if available credits that available [32:59] credits are the user available credits [33:03] okay if the available credits is not [33:06] null and if the feature requires more [33:10] credits than the user has remaining we [33:13] are going to display we're going to lock [33:15] the specific feature so here we have the [33:17] D with position absolute left zero top [33:19] zero right zero bottom zero so basically [33:22] that div is stretched on that div right [33:26] here and it's going to lock every every [33:29] interaction to uh the PN div so that div [33:33] inside there will have an SVG icon and [33:36] that SVG icon is the lock SVG icon you [33:39] can find this icon if you go into hero [33:42] icons click the very first link then [33:45] type lock right here and this is the [33:48] icon what I used here so the same SVG [33:51] icon then down below we're going to have [33:54] div you don't have enough credits for [33:56] this feature go and then I'm going to [33:59] put a link right here with the text go [34:02] buy more credits okay and the link right [34:06] now will have href just slash but we're [34:08] going to replace this with the page URL [34:12] Page Road uh on which we can buy more [34:17] credits okay down below we're going to [34:19] have additional div and we're going to [34:21] have feature description we're going to [34:23] have uh the uh information how many [34:26] credits the feature requires and at the [34:29] very bottom we're going to render all [34:31] the children okay so this feature is a [34:34] generic feature component which will be [34:37] used right now in this index jsx so in [34:41] this index jsx let's define this [34:43] function index I'm going to import every [34:46] component I need so I will need this [34:49] input error from components again this [34:51] component comes from LEL Bree I will [34:54] need um input label text input PR [34:57] primary button uh use form is something [35:00] which is uh imported from inertia JS [35:03] react and I'm going to explain what this [35:05] use form does that's that's the um [35:07] correct way interact how you can [35:10] interact with a form data in inertia so [35:13] and I'm going to also import that [35:15] feature component what we just described [35:18] okay then let's accept feature and [35:20] answer and this feature and answer are [35:23] the properties we are passing from [35:26] feature one [35:28] controller from here okay so we get this [35:32] feature an answer and then I'm going to [35:34] declare a form using use form and this [35:38] use form returns an object and that I'm [35:41] going to destructure that object and [35:42] take out data from there set data method [35:47] I'm going to get the post method and [35:49] using this we're going to send the data [35:51] to the server we're going to have resit [35:53] function we're going to have errors and [35:55] processing flag as well in I'm going to [35:58] pass you inside this use form number one [36:01] and number two as an initial data for [36:04] this use form whatever we're going to [36:06] pass right here it will be accepted [36:08] inside this data and then we can use [36:10] this data to display that number one and [36:12] number two if we need down below I'm [36:15] going to declare the submit function we [36:17] accept an event call event PR and [36:19] default and then I'm going to execute [36:21] post method okay I'm going to pass the [36:24] root name uh the I'm going to use these [36:27] root function which basically is the [36:29] function available in every component so [36:32] I'm going to use that uh function and [36:33] I'm going to pass feature one calculate [36:37] as a root name these posts accept second [36:42] argument which is an object and inside [36:44] there I'm going to pass on success call [36:46] back and on success I'm going to call [36:49] reset function okay down below I'm going [36:54] to return js6 I'm going to use that [36:56] feature component which we just [36:58] described and I'm going to pass this [37:00] feature and answer to this feature [37:02] component inside there I'm going to [37:04] declare the form I'm going to add the [37:06] submit Handler there I'm going to Define [37:09] div inside there I'm going to have this [37:10] input label for number one and I'm going [37:13] to have text input with ID type name [37:17] value class name and on change we're [37:20] going to listen on change and get the [37:22] event and I'm going to call this set [37:24] data this set data and uh the set data [37:28] accepts two arguments the first is the [37:30] field I want to update and the second is [37:33] the value even Target value and the [37:36] initial value for this input will be [37:38] data. number one and again this data [37:41] will contain whatever we pass right [37:44] here okay awesome then I'm going to [37:46] declare input error we're going to pass [37:48] the message to this input error which [37:50] will be error. number one if there is [37:53] some sort of validation errors they will [37:55] be received right here inside this eror [37:58] okay good and we're going to provide the [38:00] class name as well so down below we're [38:03] going to have very similar div to this [38:06] uh number one it will have this input [38:09] label uh text input with all these same [38:13] properties what the number one has and [38:15] the input error as well and down below [38:18] we're going to have additional D which [38:20] will be for the button inside there I'm [38:23] going to put the primary button and I'm [38:25] going to uh give it text calculate and [38:27] and I'm going to disable the Bon if the [38:29] form is in processing [38:32] State okay and I save this and I think [38:36] there is nothing um we need to do uh at [38:40] the moment inside here so I think we can [38:43] open in the browser I'm going to log in [38:47] with [38:48] my email and [38:51] password and we're going to try to have [38:53] a look uh actually before I access the [38:56] URL let me open [38:58] authenticated [39:00] layout I'm going to find this dashboard [39:03] I'm going to duplicate these two times [39:05] and here we're going to have wrot name [39:07] feature one. index the feature name will [39:11] be feature [39:12] one and here we are going to have [39:16] feature 2 [39:18] index with feature 2 text and we need [39:22] something similar for the mobile version [39:24] as well so I'm going to scroll down [39:26] below [39:29] here we have this dashboard I'm going to [39:31] duplicate this two more [39:34] times feature one [39:37] index feature one and this is going to [39:41] be feature two [39:46] index feature two let me save this and [39:49] now we have this feature one and feature [39:51] two I'm going to click on this feature [39:52] one it renders the page and we see the [39:55] title is calculate sum calculate sum of [39:58] two numbers is the description and we [40:00] see it requires one credits if I go on [40:03] feature [40:04] two it doesn't work um probably because [40:08] we have not created this feature two uh [40:11] component so even though we have the [40:14] feature to controller and the feature [40:16] Two controller um has some content [40:19] inside there let's [40:22] open feature 2 controller we are [40:26] returning this feature 2 index that view [40:28] doesn't exist and because the inertia [40:31] was not able to return the correct [40:33] response uh it doesn't uh navigate us to [40:36] the feature two I think we can easily [40:38] duplicate now feature one I'm going to [40:42] come to feature one duplicate paste this [40:46] inside Pages this is feature one copy [40:48] and I'm going to rename this into [40:51] feature 2 and let's open this feature 2 [40:54] index and I'm going to search for [40:59] Feature Feature one here and I think the [41:02] only usage is whenever we submit the [41:04] form again at the moment feature one and [41:07] feature two pages are very very similar [41:09] to each other but um I just demonstrated [41:12] how you can have multiple features and [41:14] obviously if you have different features [41:16] like game speech to text or image [41:18] restoration you can have absolutely [41:20] different content HTML content or [41:23] functionality inside each own component [41:26] feature component [41:27] okay so right now we have this feature [41:29] two defined already and I'm going to [41:31] click this feature two let's and yeah we [41:34] redirected calculate difference [41:36] calculate difference of two numbers and [41:38] requires three credits okay this is [41:41] awesome and before I test the [41:43] functionality I'm going to put also in [41:45] the nav bar the number of credits the [41:48] user has let's open authenticated layout [41:52] again scroll down below and find that [41:54] drop- down section right here and above [41:58] the drop- down div uh I'm going to add [42:01] this pan with some tle on CSS classes [42:04] and I'm going to put an image right here [42:06] which will be coin image uh I'm going to [42:09] also show this image to you but that's [42:11] actually a coin image which you can [42:13] easily get from Google any coin image [42:16] basically will work this is a just my [42:18] example okay and then next to the image [42:20] we're going to have the number of [42:22] available credits on the user okay so we [42:26] have that user accessed in this [42:28] authenticated layout uh and just like [42:31] this we can uh print how many credits [42:34] the user has then down below I'm going [42:36] to create a link and give it some tal [42:40] and CSS classes and give it text get [42:42] more okay the user has 10 credits to get [42:46] more just click right here at the moment [42:48] the href is just an empty um the slash [42:51] uh but later we're going to implement [42:53] that to go to the purchase credits page [42:57] each so if I save this and reload right [42:59] now I see 10 credits and get more right [43:03] here I'm going to add right here Gap [43:07] three to create more Gap uh between [43:10] these uh two elements and I'm going to [43:13] also uh put right here the image for [43:18] coin here is the image which I added in [43:21] Public Image folder and once I save that [43:27] in the browser I reload and I see coin [43:31] image right here 10 credits and get more [43:34] okay I think this is awesome and I want [43:36] to test now the functionality I'm going [43:39] to type one here two here and hit the [43:41] calculate and we have this error Call to [43:44] undefine [43:46] um undefine method up us decrease [43:49] credits okay I think it might be called [43:52] differently user PHP let's scroll down [43:55] below we call [43:59] this decrease okay it should be decrease [44:04] credits right so I just hit the [44:06] calculate once again and now I see [44:09] result of calculation is three we see [44:11] the number of credits we are decrease by [44:13] one and that's that's cool let's go into [44:17] feature two and provide like four and [44:20] two here hit the calculate result of [44:23] calculation is two and the number of [44:26] credits is now six I'm going to try this [44:30] two more times so that I'm going to just [44:33] run up the credits and let's see what [44:35] happens cck calculate and now look at [44:38] this so we saw the result and then this [44:40] feature got locked you don't have enough [44:43] credits for this feature go buy more [44:46] credits this buy more credits is not [44:48] valid Link at the moment it's going to [44:50] go to the homepage but you get the idea [44:52] we're going to implement that and this [44:54] link and this like the get more link [44:57] we'll do the same thing and open that [44:59] credit page but so far this is awesome [45:02] and this is [45:04] good now let's start working on the [45:07] credit controller which will be [45:10] responsible for purchasing of the [45:13] credits PHP artisan make [45:18] controller [45:21] credit controller I'm going to hit the [45:24] enter let's open this credit controller [45:27] and this should render the credit index [45:30] view which I know I I haven't written [45:33] this but I know that I'm going to do [45:35] this so I'm going to go under resources [45:38] JS pages and I'm going to create right [45:42] here credit SL index jsx [45:48] file okay awesome now let's start with [45:52] the credit [45:54] controller let's define a couple of [45:56] methods right here I'm going to Define [45:58] index which will be for rendering the [46:02] pricing packages then we're going to [46:05] have buy credits which is going to be to [46:08] buy a specific credit okay uh buy a [46:11] specific package and here we accept also [46:14] package we're going to Define rules as [46:15] well then we're going to have the [46:17] success callback and this is going to be [46:20] the stripe success URL whenever the [46:23] purchase was completed successfully will [46:25] be completed successfully user will be [46:28] redirected to the success callback we're [46:31] going to also have cancel URL and down [46:34] below I'm going to also add a web hook [46:36] for stripe okay before I proceed right [46:40] here I'm going to install stripe I'm [46:42] going to bring up the terminal and [46:44] execute composer require stripe SL [46:49] stripe [46:50] dphp so we need this [46:53] SDK stripe PHP package was installed and [46:57] then I'm going to open uh my stripe [47:00] dashboard which is right now in test [47:02] mode sandbox mode and I'm going to get [47:04] the secret uh Ral secret uh test key [47:08] right here so and I'm going to copy this [47:10] test key and I am going to put that [47:13] inside en okay so inside enan let's [47:19] open right [47:22] here and at the very bottom I'm going to [47:24] call this stripe [47:28] secret key and I'm going to paste my [47:31] secret key right here now let's open [47:34] create controller again and proceed and [47:36] start rendering um packages so we're [47:41] going to select all the packages what we [47:43] have in the database we're going to [47:45] select active features what we have in [47:48] the database and then I'm going to [47:50] render credit index react component and [47:55] I'm going to pass packages in features [47:57] but I'm going to pass them as [48:00] resources okay so this you should use [48:03] resources whenever it's um it's [48:06] necessary and applicable okay I could [48:09] not use resources Because the actual [48:12] fields for this package model is very [48:16] identical to the um what whatever I'm [48:19] going to return from this package [48:21] resource but I try to encourage you to [48:25] use resources whenever you are using [48:28] inertia application with LEL I don't [48:30] want you to get used to some bad [48:33] practices that's why I try to always use [48:36] resources when you have this like a full [48:40] stack application with inertia where [48:43] every information passed to react [48:45] component is actually visible for any [48:48] user so we are passing packages and [48:50] we're passing features we actually have [48:52] feature resource already created we're [48:54] going to import everything in a moment [48:57] but we don't have package resource [48:59] created yet okay so I'm going to bring [49:02] up the terminal and I'm going to execute [49:05] PHP artisan [49:08] make [49:10] resource package resource and I'm going [49:13] to hit the enter and let's open this [49:15] package resource and I'm going to change [49:18] this into an array and if we just open [49:22] Package PHP we have three Fields right [49:26] here and plus we also have this ID so [49:31] what I'm going to do is just um return [49:35] maybe it even autocompletes that [49:39] name we are going to have [49:47] price and we're going to have [49:55] credits [50:00] okay so we have this package resource [50:02] ready I'm going to close that and let's [50:04] continue in the credit controller okay [50:06] I'm going to import everything at the [50:07] bottom at at the um top right here so [50:13] then we proceed and we move into um [50:17] additional properties we're going to [50:19] pass into this credit index we're going [50:20] to pass the success message and we're [50:23] going to pass the error message to this [50:26] and the success and error messages will [50:28] be pushed into session from the success [50:31] and cancel methods okay now let's move [50:34] on and implement this buy credits which [50:37] is uh inside which we're going to create [50:40] the stripe session and redirect user to [50:43] stripe checkout page we're going to get [50:46] this stripe secret key from Ian which we [50:49] already put right there we're going to [50:52] create the stripe client and then from [50:54] the stripe client we're going to create [50:56] checkout s session this function create [51:00] accepts an array and inside there we [51:02] need line items line items is array of [51:05] arrays and we're going to pass the very [51:08] first item inside here we're going to [51:10] have the price data and we're going to [51:13] have quantity one for this okay so [51:17] basically in stripe those line items is [51:20] going to be products so and whatever [51:23] we're going to pass uh will be actually [51:26] created in stripe as product which we [51:28] actually don't care because we there is [51:30] something we want to buy we're going to [51:32] buy credits which if it will be product [51:35] in stripe we don't care but there are [51:38] certain fields we have to provide like [51:41] the currency product data for example [51:44] and inside product data we have to [51:46] provide the name and inside name we [51:48] provide package name concatenated with [51:52] how many credits that package has for [51:55] example for gold gold package this is [51:57] going to be [51:59] gold- 500 credits okay this is going to [52:02] be product [52:04] name so whenever you check your stripe [52:06] dashboard uh what items are sold mostly [52:10] you might see inside products called 500 [52:15] credits so and we're going to also have [52:17] the unit amount which is the price and [52:20] we're going to have price in cents so [52:23] I'm going to multiply package price on [52:25] 100 at the uh down below we're going to [52:28] have next to the line items we're going [52:30] to have mode payment okay and using this [52:33] we created the check out session we're [52:35] going to provide also success URL and [52:38] cancel URL and those going to be the [52:40] roles we will Define but we are using [52:43] this third parameter true for generating [52:47] absolute URLs we need those absolute [52:49] URLs uh because they will be passed to [52:52] stripe and then we will the the stripe [52:55] will redirect us back [52:57] to the um page so we need them to be [53:00] Absol [53:00] URLs so and I'm going to also create [53:04] transaction okay I'm going to provide [53:06] status pending the price package price [53:09] credits package credits we're going to [53:11] provide session ID we're going to [53:13] provide the authenticated user ID and [53:16] the package ID as well okay and then [53:20] we're going to redirect user to this [53:22] checkout session URL and basically this [53:26] method is finished okay let's scroll [53:29] down below and in the success basically [53:32] we are going to uh redirect user to [53:35] credit index which will be the [53:39] following action okay credit index and [53:44] I'm going to provide with success [53:46] message you have successfully bought new [53:50] credits for cancel we're going to [53:53] redirect again to credit index how [53:56] however we're going to provide error [53:58] message will be there was an error in [54:02] payment process please try again okay [54:06] and the next thing is web hook the [54:09] stripe will send requests to us in the [54:12] background that this checkout process [54:16] was completed successfully and then we [54:18] need to take care of that and we have to [54:23] um we have to basically do the necessary [54:26] things like increase the users available [54:28] credit and so on so let's proceed here [54:31] so we are going to get the um secret so [54:35] this endpoint secret is actually [54:38] necessary [54:40] to uh to make sure that the web Hook is [54:43] going to work successfully okay so we [54:45] have this stripe web hook key which [54:49] we're going to put inside en en I'm [54:52] going to open en and at the moment I'm [54:54] going to put this right here with m [54:56] string but we're going to populate this [54:59] um a little bit later okay so then we're [55:03] going to get the entire [55:05] payload we're going to get the HTTP [55:08] stripe signature header and by the way [55:10] this is also written in the stripe [55:12] documentation and I'm going to fill this [55:14] part and then I'm going to show where [55:16] you can find that okay so I'm going to [55:19] define the event which will be n and [55:21] then inside I'm going to do try catch so [55:24] I'm going to try to construct it an [55:26] event based on the following information [55:29] I'm going to pass the payload entire [55:31] payload I'm going to pass the signature [55:33] header and I'm going to pass the [55:35] endpoint secret so if the event is [55:39] constructed successfully it means that [55:43] the request is coming from stripe it's a [55:45] valid request and we get we can get the [55:49] information from there and that's [55:51] awesome and we need to take care of this [55:54] properly okay so however we need catch [55:58] as well I'm going to add two catch [56:00] statements here unexpected value [56:03] exception and signature verification [56:05] exceptions so and in both cases simply [56:08] I'm going to return uh with the response [56:11] 400 status code and down below I'm going [56:14] to check if the event exists so if the [56:17] event was created right here what is the [56:20] event type so if the event type is [56:22] checkout session completed this is [56:24] exactly what we are interested in [56:27] then we need to do something so in [56:29] default case we simply write um received [56:32] unknown even type however in this case [56:35] we're going to get this session and we [56:37] get this session from even data object [56:40] so this is the same uh session object we [56:44] created uh right here and that session [56:48] has its own ID which we saved in the [56:50] transaction session ID column so now [56:53] based on that session I I'm going to [56:56] select the transaction from the database [56:59] the first transaction if the transaction [57:01] exists and if its status is pending I'm [57:05] checking it status if it's pending [57:06] because I don't know stripe might send [57:09] this more than once uh for me so I just [57:12] need to be sure that I don't do any un [57:15] like weird and incorrect things if [57:18] stripe send this twice so if this status [57:21] is pending in this case I set this [57:24] transaction status to be paid and I save [57:26] the transaction but I'm going to also [57:29] access the transaction user who made the [57:33] transaction and I'm going to increase [57:35] that user's available credits with the [57:39] transaction number of credits whenever [57:42] we created the transaction right here we [57:44] provided how many credits user is trying [57:48] to buy and we took that credits and add [57:52] it to the users available credits and [57:56] finally we're going to save the [57:57] transaction user okay this is perfect [58:00] and at the bottom of this uh web hook we [58:03] are going to return with the response of [58:07] empty string but the status code is 200 [58:10] and that's going to be totally enough [58:12] for stripe if we return status code 200 [58:16] this means that we got the web hook and [58:19] we handled [58:20] that now I am going to [58:24] open index jsx and let's work right here [58:28] so this is the um react component [58:32] actually we need to import certain [58:33] things so let's scroll up and I'm going [58:36] to do these Imports I'm going to import [58:37] the feature resource package resource [58:40] I'm going to import this uh package um [58:44] and feature and [58:45] transaction uh and we also need to [58:48] import this facade out because we are [58:50] using here whenever we are assigning the [58:53] user ID I think there's nothing um to [58:57] import um except that so we are good in [59:00] the credit controller uh now I'm going [59:03] to work inside this file credit index [59:06] and we we are passing these packages and [59:08] features and success and error and we [59:10] need to handle this properly okay so I'm [59:12] going to Define this function and I'm [59:14] going to also import all the necessary [59:16] components authenticated layout I'm [59:19] going to import the head and I'm going [59:21] to create new component for this credit [59:25] pricing card [59:27] okay and there's going to be three tiers [59:29] uh one for each package and I'm going to [59:31] create separate component for this okay [59:34] but right now I assume that the [59:35] component is already there so I'm going [59:37] to do this import [59:39] beforehand then I'm going to accept [59:41] inside index couple of properties like [59:44] out packages and [59:46] features and I'm going to also accept [59:48] success and error okay we are passing [59:51] these packages feature success and error [59:53] from the credit controller from here but [59:56] remember that the out prop is passed [59:58] from handle inertia JS request uh middle [60:02] wear okay then we're going to get the [60:05] number of available credits for the user [60:08] and then we're going to render js6 so [60:11] here I'm going to use authenticated [60:12] layout with user and header then I'm [60:15] going to provide title right here and [60:18] down below uh we're going to have some [60:20] boiler plate layout code and if the [60:23] success is given then I'm going to [60:26] render the success message with [60:28] background green if the error is given [60:31] and if it's if it exists I'm going to [60:33] render the error message with background [60:35] red okay then I'm going to do additional [60:38] div and uh inside there I'm going to [60:41] have one more div and image with the [60:44] coin icon so we have the we have the [60:48] following coin icon and I'm going to use [60:52] the same coin icon [60:54] okay and inside there I'm going to just [60:57] write you have X whatever is available [61:01] credits and down below I'm going to [61:03] render these credit pricing cards and [61:07] I'm going to pass packages and features [61:10] to that [61:12] okay so now we need to create these [61:15] credit pricing cards and we're passing [61:17] this uh packages data and features data [61:20] because we are passing them as a [61:23] resources and the resources uh resource [61:27] collection basically has this data if [61:29] you want to actually access that you [61:32] need to access this through [61:34] data okay [61:36] good uh now let's create this whatever [61:39] is the name credit pricing cards [61:41] component I'm going to do this right [61:43] here do [61:47] jsx now let's define these uh credit [61:50] pricing cards and um I'm going to use [61:54] the page import that use page from [61:56] inertia JS react and I'm going to use [61:59] that page right here to get the csrf [62:03] token okay the csrf token is something [62:06] we're going to add uh in inside the [62:09] middle we which doesn't exist yet but [62:11] we're going to also accept these [62:12] packages and features we are passing [62:16] from here which is totally [62:18] clear however let's add this csrf token [62:21] so I'm going to open handle inertia JS [62:24] request and just like like we are [62:26] putting this out I'm going to put right [62:29] here [62:30] csrf token will be [62:35] csrf [62:36] token okay I'm going to save that and [62:40] we're good now I'm going to return a jsx [62:44] section with some Talon CSS classes div [62:47] another div inside there I'm going to [62:49] have this H2 uh it's that's going to be [62:51] a promotional text the more credits you [62:53] choose the bigger savings you will make [62:55] and before before I proceed I'm going to [62:56] show you the template I use for this [62:59] pricing um table which you can also get [63:02] from uh flow bite so I use this flow [63:06] bite pricing cards something like [63:10] this [63:12] um ton CSS pricing cards so this is [63:16] exactly what I used I'm going to switch [63:17] into dark mode and you're going to see [63:20] okay so this this is the promotional [63:22] text which obviously I changed and we [63:25] have three price cards with features so [63:27] this is the exact same I'm using the [63:30] exact same layout I actually uh got the [63:33] code and I copied that okay I also have [63:36] these SVG icons in my [63:39] code okay now let me proceeded you can [63:42] get this uh entire HTML and modify as [63:44] you need or you can just follow with me [63:46] and type that HTML [63:49] content okay then I'm going to Define [63:51] another div and uh iterate over packages [63:55] okay [63:56] and for each package I'm going to render [63:59] div and for each package I'm going to [64:02] render uh the following div okay inside [64:06] there we're going to have H3 which will [64:08] be the package name we're going to have [64:11] also the package price and the number of [64:15] credits the package includes and we're [64:17] going to also have an unordered list of [64:20] features so I'm going to iterate over [64:22] all the features which is passed to the [64:24] credit pricing cards [64:26] and um then I'm going to render Li for [64:30] it and print the feature name okay [64:34] however before this feature name I'm [64:36] going to also put an SVG and again this [64:39] is the same SVG what what uh is [64:42] available in the following [64:44] template [64:46] um right here this one okay cool now if [64:51] I scroll down below I'm going to create [64:53] four okay so there is this [64:56] button uh right here but only button is [64:58] not enough I'm going to have a form and [65:01] submit that form to [65:04] the uh let me close unnecessary files to [65:08] this credit controller buy credits and [65:10] I'm going to pass the package of which I [65:13] want to buy okay so once I have the form [65:19] um the action will be wrote credit buy [65:22] and I'm going to provide the package [65:23] which I want to buy the road does [65:25] doesn't exist yet and we're going to [65:27] create that no big deal the method is [65:29] post and we're going to do traditional [65:31] form submission we are not going to do [65:33] inertia JS type of form [65:36] submission okay then inside this form [65:39] we're going to have input type hidden [65:41] with csrf token because we're going to [65:44] do form submission we need this csrf [65:46] token as well okay and I'm going to have [65:49] also button with a lot of Talan CSS [65:51] classes this is the same button and uh [65:55] we have have this get started or [65:57] whatever we can call this whatever like [65:59] buy more [66:00] credits okay so I think this part uh [66:04] this component is actually ready and we [66:07] are importing this in the uh credit [66:10] pricing cards the only thing what we [66:12] don't have is rules these credit buy [66:15] rules and other rules so we are going to [66:18] open web.php and create that rules uh [66:24] I'm going to do this inside right here [66:26] this out and [66:27] verified uh we already have these [66:30] feature one and feature two roots and [66:33] then at the bottom right here I'm going [66:36] to add uh road to buy credits and I'm [66:40] going to provide credit controller index [66:43] and let's give it also a name credit [66:45] index okay I'm going to Define another [66:48] rout uh for bu credit success which will [66:51] be credit controller success and the [66:53] route name will be credit success as [66:54] well I'm going to Define in the same way [66:57] cancel [66:58] root and I'm going to define a post [67:02] request for buy credits package okay [67:04] this is uh how we're going to redirect [67:07] to to [67:08] stripe this is going to be credit [67:10] controller by credits which is actually [67:13] the following method and it has this [67:15] credit by which we are using right here [67:19] okay so I think this is great and we are [67:23] going to also Define web hook regarding [67:26] web hook you should have few things uh [67:29] in your mind first is that uh stripe [67:33] will make request on web hook with the [67:37] um as unau unauthenticated user so we [67:41] are not going to put this web hook um [67:44] right here okay we should put this [67:47] outside of any middle we we should put [67:49] this right here so this is the first [67:52] thing second thing is that we need to [67:57] disable and by the way we need to import [67:59] this uh crate controller uh so let's [68:02] just do the [68:03] import here we have that uh so the [68:06] second thing is that stripe will make [68:09] the post request on the following web [68:12] hook URL and we are going to disable [68:15] csrf validation for that specific [68:18] endpoint so right now I'm in Lal 11 and [68:21] Lal 11 has done it slightly differently [68:25] so we're going to open app.php from [68:28] bootstrap folder okay and here we have [68:31] this middle wear and on that middle wear [68:35] I am going to execute a method called uh [68:41] validate csrf tokens and that [68:45] accepts um accepts an accept array so [68:50] it's fine so uh the validate CSF token [68:53] excepts an array uh and that's going to [68:56] be [68:56] exclude um roots and that's going to be [69:00] buy Das credits SL web hook so the CSI [69:06] validation should happen besides that [69:10] route okay once I save [69:14] this uh I want to open [69:18] now feature [69:20] jsx and if you scroll down below we have [69:23] the following h which I'm going to [69:26] change now [69:29] into proper root and it's going to [69:33] be [69:35] root credit [69:37] index and I'm going to do something [69:40] similar in authenticated [69:43] layout uh we have [69:46] the where is it right here we have this [69:50] uh Slash and we're going to need [69:53] root credit do [69:56] index so I'm going to save [70:00] this and now let's have a look in our [70:03] browser okay whenever I click this on [70:05] buy more credits uh we have the [70:08] following error this [70:11] Credit Credit pricing [70:14] cards [70:15] [Music] [70:16] um okay that doesn't exist where did I [70:20] create [70:22] that credit pricing cards [70:29] credit [70:31] pricing [70:35] cards yep it should be in plural we call [70:38] this credits pricing cards and I should [70:42] call [70:45] this maybe we should even call this [70:48] packages pricing cards uh and let's go [70:52] into credit index and I'm going to [70:54] change this [70:56] into packages pricing cards and then [71:00] we're going to fix the import packages [71:03] pricing cards now let's have a look I'm [71:05] going to click this buy more credits and [71:07] we are redirected to that page your [71:10] credits okay you have zero credits the [71:12] more credits you choose the bigger [71:13] savings you will make and here we see [71:16] the all the plans the packages and we [71:19] see also this calculate sum calculate [71:22] difference um as separate features [71:26] I think this is awesome whenever I click [71:28] on this we should be redirected to this [71:30] trip [71:31] page okay we are redirected this is [71:34] awesome and the one last thing is to uh [71:37] test the web hook functionality okay so [71:41] for this let me open the stripe [71:44] dashboard and inside search I'm going to [71:46] search for web hooks okay and we're [71:50] going to do this local testing so uh I'm [71:53] going to do this add local listener I I [71:57] whenever I Was preparing for this [71:58] project I actually added this already [72:00] but I'm going to add this once again [72:04] okay so what we need to do first is to [72:07] download the CLI from the stripe okay [72:10] then we are going to do the stripe login [72:12] then we're going to do the stripe uh [72:15] forwarding to the local project and then [72:17] we're good to go and on the right side [72:19] you can also see that uh the the code [72:24] which which we wrote in the web hook [72:27] okay to get the event and validate [72:29] construct the event and validate that [72:32] and then do the corresponding things um [72:35] for bason even type okay just make sure [72:39] you that you have this um stripe CLI so [72:42] I'm going to click this download CLI [72:43] open this in a new tab okay here we have [72:47] a different operating systems and I'm [72:49] going to go to Windows and uh we have to [72:53] download the following file from GitHub [72:55] so I'm going to open this in a new tab [72:58] and I'm going to search for The [73:00] Following part right there this is it [73:04] this is what I'm going to download the [73:06] download is going to start I'm going to [73:08] do this inside [73:11] downloads so here I have downloaded that [73:14] zip file I'm going to extract it that [73:16] and inside there we have the stripe [73:17] xcept okay I'm going to open git bash [73:20] right here or you can open CMD and [73:22] navigate to the following path the main [73:25] think that you're going to have some [73:26] terminal you will need that so then [73:29] right here in this terminal let me zoom [73:32] in uh we are going to log in first of [73:34] all based on the um based on the [73:38] documentation so I'm going to close [73:39] these two tabs okay and we're going to [73:41] do stripe login but because we are on [73:44] Windows we're going to execute [73:47] stripe do XA [73:51] login uh what's that I think we need [73:55] / stripe XA [73:59] login okay [74:01] good now we're going to click on this to [74:04] open that stripe dashboard it is opening [74:08] and from here we need to log in and it's [74:11] prints the following puring code joyful [74:13] warm whatever and we have the same code [74:16] so I'm going to click on L access access [74:18] has been granted let's close this and [74:21] right here we can see that we are [74:22] authenticated and the key will expire in [74:25] 90 uh days and now we can do this [74:29] forwarding so I'm going to copy that [74:31] into clipboard and I'm going [74:34] to paste this right here [74:39] oops let me copy this and paste here and [74:44] we're going to change the port in the [74:46] web hook URL so uh any web hooks sent [74:50] from stripe will come should come from [74:53] Local Host port 8,000 SL [74:57] by- credits SL web hook this is the URL [75:03] on which we handle the web hook so I'm [75:05] going to hit the enter right here sorry [75:08] again so do SL [75:11] strip. [75:13] XM okay let's wait one second and here [75:16] we see that the connection has been [75:18] submitted and the web hook signing [75:20] secret is this so this is what I am [75:23] going to copy [75:25] this one and this is what I am going to [75:28] put [75:31] inside in [75:36] file for the stripe webook key right [75:39] here okay so now I save that and I [75:43] should have this web hook opened and [75:45] observing that and now I'm going to test [75:48] this functionality so this is my [75:50] previously open page let me test if this [75:53] still valid uh test at example.com we're [75:58] going to provide test stripe card [76:03] details just make sure you provide any [76:05] data in the future any CVC and let's [76:09] provide any name here and I'm going to [76:11] click on pay and I'm going to open this [76:13] web hook um and let's see as you can see [76:16] the status code returned from our web [76:18] Hook is 200 which means it successfully [76:21] processed the incoming request and it [76:24] should have up updated the number of [76:27] credits on the user so if you open now [76:29] in the browser we're going to see that [76:31] the user has 20 credits and feature one [76:34] and feature two both are actually [76:38] available please also keep in mind that [76:41] whenever you're doing the stripe [76:43] checkout process your computer time [76:45] needs to be uh precise basically even [76:49] five minutes out of sync your computer [76:51] time will cause problems during this [76:54] checkout I have this issue personally [76:56] that's why I'm telling this to you just [76:58] make sure you have the correct time set [77:00] on your computer because then the [77:02] signature validation inside web hook [77:05] simply will fail okay and it will not [77:08] succeed okay that's perfect so we have [77:11] now implemented this um automatic credit [77:14] fing functionality and that's awesome [77:16] user can choose any tier they want and [77:19] they can fill the number of credits [77:20] right there now I'm going to implement [77:22] the dashboard inside which I'm going to [77:24] show [77:25] all the used features the user has [77:28] basically used okay so let's open now vs [77:32] code and I'm going to generate new [77:34] controller for the dashboard and I think [77:37] we don't have um dashboard controller [77:40] don't we let's check this web [77:42] roads where we yeah we don't have the [77:46] controller dedicated controller for the [77:47] dashboard so let's execute PHP artisan [77:53] make control [77:55] controller dashboard controller let's [77:59] hit the enter the controller was created [78:01] this is awesome we are going to display [78:04] used features okay so I will need to [78:08] also create used feature resource so I'm [78:12] going to execute PHP artison make [78:17] resource used feature resource let's hit [78:22] the enter okay that was also [78:25] created [78:31] awesome and now we're going to write um [78:34] the corresponding Fields right here [78:37] we're going to populate the dashboard [78:38] controller and I'm going to also open [78:41] dashboard js6 and I'm going to render [78:44] table right here uh like for the table [78:47] I'm going to use also table component [78:49] from this flow bite so if I search for [78:52] table right here we can click on the ver [78:54] first link and uh I'm going to show you [78:57] the the uh UI first so this is how table [79:00] looks like this is Tyle one CSS table [79:03] the First Column basically is a in a [79:07] bold in a white color so it has [79:09] different styles so if we expand this [79:11] code and see right here the First Column [79:14] has different styles okay so I'm going [79:16] to basically use the same table you can [79:19] copy and paste I'm going to quickly um [79:22] write it right here okay okay awesome so [79:25] let's start with the dashboard [79:28] controller we do I have this code I lost [79:31] it okay here we go let's create index [79:34] function right here and inside there I'm [79:36] going to select used features I'm going [79:39] to select this used features with [79:41] feature because we're going to display [79:43] the feature name also in the table then [79:46] I'm going to sort them um I'm going to [79:49] first first of all filter them by the [79:51] currently authed user ID and then I'm [79:53] going to sort them by I created a date [79:57] okay so I'm selecting all the features [79:58] for the current user sorting them latest [80:00] used feature at the top and I'm going to [80:03] also call paginate so I'm going to get [80:05] this paginated response and then I'm [80:08] going to render the dashboard jsx [80:10] component and I'm going to pass these [80:12] used features as a a used feature [80:15] resource collection okay so awesome [80:19] let's go into uh yeah let's actually [80:21] import uh we're going to import the used [80:24] feature uh resource and we're going to [80:27] need uh the used feature as well and I [80:30] think we're going to need to import Ina [80:33] as well U right here now let's go into [80:37] used feature resource and we are going [80:40] to return ID we're going to return [80:42] credits we're going to return this [80:44] feature which is relation to the feature [80:46] object and we're going to pass this into [80:49] new feature resource and then this [80:51] feature will be an instance of new [80:53] feature resource and and we're going to [80:55] return create date but we're going to [80:57] format this nicely into our own format [81:00] and we're going to return the entire [81:02] data as well which will be extra [81:05] information used for this feature now [81:07] let's go into J into dashboard jsx and [81:11] first of all I'm going to use uh like [81:14] take this prop used features which we [81:16] are passing from here okay so we need [81:20] this use features then I'm going to [81:22] delete that that part completely [81:25] uh and I'm going to uh use the template [81:29] I mentioned or this table okay so we're [81:32] going to need this position relative [81:34] overflow X Auto what we have right here [81:37] inside there we're going to have table [81:39] I'm going to add some t one CSS classes [81:41] to this table inside there we're going [81:43] to have t head with Ty one CSS classes [81:45] again inside there we're going to have [81:47] TR and th couple of th's first will be [81:51] feature second will be credits then [81:53] we're going to have date and finally [81:55] we're going to have additional data down [81:58] below we're going to have t body as well [82:00] and we're going to iterate over used [82:02] features data okay this used features is [82:05] an instance of a collection so we're [82:07] going to take data out of it and then [82:10] iterate over the data using map function [82:12] and we're going to use that used feature [82:14] variable to render TRS so inside each TR [82:18] we're going to add key we're going to [82:20] add Talon CSS classes to each TR and [82:23] then we're going to display play uh the [82:25] in the first the first element of this [82:27] TR basically will be th okay this will [82:31] be in a different color as it is written [82:33] right here so the th will have its own [82:37] different uh Talon CSS classes and then [82:40] we're going to display the used feature [82:42] do feature which is relation to feature [82:45] do name after th we're going to display [82:48] a used feature number of credits we're [82:51] going to display used feature created [82:53] that and then we're going to display [82:55] used feature. data so those are all the [82:58] properties which we returned inside our [83:01] resource okay and down below I'm going [83:03] to do one check if the used feature data [83:06] length does not exist which means that [83:08] if the user doesn't have any features [83:10] used yet I'm going to display another TR [83:15] and inside the TR we're going to have TD [83:18] with call span 4 basically I'm going to [83:20] combine all the four columns uh with [83:24] text Center and padding and inside there [83:27] I'm going to display you don't have used [83:29] any features [83:31] yet okay that's going to be for new [83:33] users now I'm going to save this let's [83:36] open web.php I'm going to remove this [83:39] function and I'm going to replace this [83:42] with dashboard [83:47] controller [83:49] index uh just make sure we have the [83:52] dashboard controller imported right here [83:54] this is awesome we have that now if I [83:58] save this actually because we need the [84:00] same middle Weare in the dashboard [84:02] controller maybe we can just remove [84:05] middle wear from here and maybe we can [84:08] just take this out and insert this [84:11] entire this group without and verified [84:15] middle wear I'm going to paste this [84:16] right here and let's move this name down [84:19] below okay cool now let's open dashboard [84:23] and have a look here we see the table so [84:25] here we see the future uh feature name [84:28] calculate difference we see sum whatever [84:32] number of credits the feature required [84:34] at the time the date when it was used [84:36] but we don't see anything inside [84:37] additional data that's strange let's go [84:41] into dashboard jsx and have a look we [84:43] have this used feature data let's [84:45] actually print entire used feature using [84:49] Json [84:50] stringify and I'm going to print the [84:52] entirely used feature let's see what we [84:54] have here we have ID we have the [84:58] feature uh we have created it but the [85:01] data is null now let's check the [85:04] database what is data [85:06] there uh okay so let's access the [85:10] database using [85:12] Tinker [85:15] up models oops excuse me so up [85:23] moduls used [85:26] feature let's get [85:30] all okay the data is null in the [85:34] database for all of [85:36] them okay why is this is this null don't [85:40] we save it or maybe there's some issue [85:43] When selecting the data I'm going to [85:45] open uh I'm going to open um used [85:50] feature class and here we have this uh [85:53] cast in to data array I think the reason [85:57] is that we don't have data inside [85:59] fillable but we are actually filling [86:01] that right here through this used [86:03] feature create so we just need to put [86:06] data right here let's save this and [86:10] let's test the functionality so I'm [86:13] going to open feature one provide two [86:16] numbers hit on calculate that was [86:18] calculated let's go into dashboard and [86:21] here we see data which contains number [86:23] one and number number two let's go into [86:26] dashboard js6 and let's undo right here [86:29] and just print feature. data and we [86:34] have uh and we have [86:37] error actually that's strange what error [86:41] do we have let's see okay I see what [86:46] error do we have so the uh use feature [86:48] data is actually an array in order us to [86:51] be able to print that nicely we need to [86:54] use Json stringify again you can render [86:59] this data as you like okay you can [87:02] iterate over the keys of that used [87:04] feature data and render it if you if it [87:06] contains like um processed image paths [87:09] you can obviously render images or you [87:12] can add um additional link let me reload [87:15] the page and close these developer tools [87:18] uh you can also put additional link to [87:20] view details of the specific feature and [87:23] if that additional data contains as [87:25] image paths you can display that images [87:28] inside Details page okay so just the [87:30] main idea is that we have all the [87:32] information about uh how the user used [87:35] the specific feature what data was [87:38] provided we can even save result right [87:41] here you can easily do this in the um [87:44] feature One controller let's open this [87:46] and give you hint so you can calculate [87:49] some of these two numbers at at the top [87:51] of this used feature create function and [87:54] and you can put this in the result [87:55] variable and you can put that result [87:57] into Data as well and pass the result [87:59] right here so you can put the actual [88:01] result of the feature inside data and [88:04] save this in the database as well it's [88:06] it's it's up to you how you're going to [88:08] decide but we have the dashboard which [88:10] displays all that information um we [88:12] don't have the pagination I'm not going [88:14] to implement the pagination but you have [88:16] everything what you need if you uh see [88:18] what is this used features right here it [88:23] basically is an object which contains [88:26] let me stringify this for you so it [88:30] contains uh data which we already [88:33] iterated but it contains also additional [88:37] information such as where it [88:41] is it contains some meta information and [88:44] that meta contains what is the current [88:46] page from to it contains all the [88:49] pagination links okay you just need to [88:51] iterate the those meta links and render [88:55] them nicely uh I'm just going to provide [88:57] right here undefined and two and now we [89:01] have this um much more um nicely [89:05] rendered actually if you want to see how [89:07] to implement the pagination as well you [89:09] can check my other projects with Lal and [89:11] react I have a couple of projects [89:12] already and those include the pagination [89:15] part as well but it's pretty [89:16] straightforward that's why I'm not going [89:17] to spend uh more time on this specific [89:21] feature let me remove this pre right now [89:26] and we're going to have this table [89:27] remaining now the last thing I'm going [89:30] to do is I'm going to change the [89:32] homepage which right now displays this [89:34] uh updated L 11 homepage and instead I'm [89:38] going to display uh cards like similar [89:41] to this lost card and I'm going to [89:44] display one card for each feature and [89:49] for this I'm going to create a new [89:51] controller for the homepage and I'm I'm [89:54] going to also update the root right here [89:57] instead of this I'm going to render [89:59] those [90:00] features okay I'm going to close every [90:02] other Tab and I'm going to create Now [90:06] new controller home controller PHP [90:09] artisan make controller home controller [90:14] let's hit the enter let's open the home [90:16] controller and right here I'm going to [90:19] Define index function and inside there [90:23] I'm going to uh do the [90:25] following first of all I'm going to [90:27] select all the features uh not all all [90:30] but I'm going to select only active [90:32] features if the feature is disabled we [90:34] don't want it to be displayed on the [90:36] homepage then I'm going to use this [90:38] inertia render uh rendering the welcome [90:41] jsx component and we're going to pass [90:44] these features uh as through this uh [90:46] feature resource collection but we're [90:49] going to also pass two additional [90:51] variables which are by itself passed [90:54] from uh from here which comes with the [90:57] L's default installation can login and [91:00] can register so we're going to pass [91:02] those two variables as well however we [91:04] don't need this L Val version and PHP [91:07] version and I'm going to remove that so [91:10] right here we're going to pass can login [91:12] and can register okay and at the top [91:15] let's import uh we need a feature [91:18] resource we need feature model we need [91:21] this uh rout fac side and we also need [91:25] inertia class to render this welcome js6 [91:29] okay let's go into web PHP and I'm going [91:32] to remove this function and I'm going to [91:34] change this into home controller class [91:38] index name home okay and right here we [91:41] don't need inertia and we don't need [91:43] application so I can remove them already [91:46] and we need to open welcome js6 so right [91:49] now the Lal go to view extension refers [91:53] to Blade file file if I control and [91:55] click on this it's going to open the [91:56] blade file excuse [91:58] me but we don't need this blade file [92:01] what we want is jsx file so I'm going to [92:04] open welcome jsx and I'm going to work [92:09] right here if you scroll down below uh [92:11] and analyze this a little bit so this is [92:14] again updated to welcome jsx file which [92:16] is in the latest L version so here we [92:19] have this image which I think is the [92:21] background image which we can actually [92:23] leave [92:24] let's open this yeah we can leave that [92:27] and then we have this div the main div [92:29] inside there we have uh another div [92:33] inside there we have this header section [92:35] we're going to leave that header section [92:37] and inside there we have one div for the [92:41] uh laravel official documentation then [92:44] another D which is going to be uh for [92:46] laracast another one and four divs [92:50] basically there are still four divs like [92:52] it was previously but just the layout is [92:55] slightly different this one will have [92:58] some Rose spine or something like [93:01] this okay now let me remove the first um [93:07] first documentation div and if we check [93:09] right now the homepage we don't see this [93:12] documentation div anymore okay and I'm [93:15] going to delete others as well and what [93:18] I'm going to do is um we just left only [93:22] one okay which is perfectly fine we can [93:24] remove this F uh footer as well because [93:27] we don't pass this Lal version in PHP [93:29] version as well so I'm going to remove [93:31] this from footer as well we can leave [93:34] this logo or we can remove it's up to us [93:37] but we are going to accept let's remove [93:40] these props we are going to accept [93:42] features as prop and the features uh [93:46] we're going to render right here so [93:48] features. [93:50] data. map we're going to get [93:54] feature and for each feature we are [93:56] going to render the following a tag so [94:01] I'm going to save this I just saved and [94:04] it was formatted nicely let me collapse [94:06] this and if we check right now on the [94:08] homepage we're going to see two [94:09] identical divs because we have two uh [94:12] features actually and we are uh [94:16] rendering two divs right here now let's [94:18] adjust the image and adjust this H ref [94:22] as well uh so this is actually a tag but [94:26] I'm going to change this into link okay [94:29] and we need to import that link right [94:32] here inside this inertia JS react which [94:34] is already [94:35] imported next we need to provide right [94:40] here feature dot root name okay now [94:46] whenever we click on this it will have [94:48] if you m if you uh if I Mouse over [94:51] you're going to see in the bottom left [94:53] corner the URL so it is feature one. [94:56] index uh sorry so that should be we [94:59] we're going to use Road and pass this [95:02] feature rot name to that so now we see [95:04] feature one as a URL and feature two as [95:07] a URL right here okay let's scroll down [95:09] below and here we have this SVG which is [95:12] I think the logo not the logo but the [95:15] actual um icon so instead of that [95:20] SVG uh I'm thinking about putting an [95:23] image right here because we have images [95:25] for each feature so image and inside [95:29] source I'm going to provide [95:33] feature. image that's going to be [95:35] probably large image oh no it is [95:38] actually perfectly fine so this is the [95:40] feature image for the um calculate sum [95:43] this is for the calculate difference and [95:45] let's finalize this right now so we're [95:48] going to Output feature. name right here [95:50] and here we're going to Output uh [95:54] feature. [95:57] description so down below we have this [95:59] SVG path something which we can leave [96:02] this I think this Arrow so now we have [96:04] two features on the homepage calculate [96:07] sum which opens this feature go back and [96:10] calculate difference which opens the [96:12] feature to and I think this finalizes [96:15] our project we have this nice homepage [96:17] where we list and show all the features [96:20] again you obviously need to implement [96:23] more complex and sophisticated features [96:25] something people Worth to pay some money [96:28] for it you can put them on your homepage [96:32] then on the dashboard user can see the [96:34] use features we have the feature Pages [96:37] itself and whenever user runs out with [96:40] its credit they can buy the predefined [96:43] package uh with the following price and [96:45] the following number of credits this is [96:48] awesome project and we also have this uh [96:50] Lal brid profile management right here [96:53] all right that's it my friends and I [96:55] hope you learned something new please [96:57] hit the like button and subscribe if you [96:59] are not yet for more videos like this [97:01] also let me know your thoughts about [97:03] this project in the comment section down [97:05] below if you want to support the channel [97:07] you can check my website the cool.com [97:09] you can buy my course or you can check [97:11] my patreon page as well thanks for [97:13] watching I appreciate your comments your [97:15] likes uh Your Love simply and I will see [97:19] you in another video