All language subtitles for enSubtitle

af Afrikaans
ak Akan
sq Albanian
am Amharic
ar Arabic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bem Bemba
bn Bengali
bh Bihari
bs Bosnian
br Breton
bg Bulgarian
km Cambodian
ca Catalan
ceb Cebuano
chr Cherokee
ny Chichewa
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
en English
eo Esperanto
et Estonian
ee Ewe
fo Faroese
tl Filipino
fi Finnish
fr French
fy Frisian
gaa Ga
gl Galician
ka Georgian
de German
el Greek
gn Guarani
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
id Indonesian
ia Interlingua
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
rw Kinyarwanda
rn Kirundi
kg Kongo
ko Korean
kri Krio (Sierra Leone)
ku Kurdish
ckb Kurdish (SoranĂ®)
ky Kyrgyz
lo Laothian
la Latin
lv Latvian
ln Lingala
lt Lithuanian
loz Lozi
lg Luganda
ach Luo
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mfe Mauritian Creole
mo Moldavian
mn Mongolian
my Myanmar (Burmese)
sr-ME Montenegrin
ne Nepali
pcm Nigerian Pidgin
nso Northern Sotho
no Norwegian
nn Norwegian (Nynorsk)
oc Occitan
or Oriya
om Oromo
ps Pashto
fa Persian
pl Polish
pt-BR Portuguese (Brazil)
pt Portuguese (Portugal)
pa Punjabi
qu Quechua
ro Romanian
rm Romansh
nyn Runyakitara
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
sh Serbo-Croatian
st Sesotho
tn Setswana
crs Seychellois Creole
sn Shona
sd Sindhi
si Sinhalese
sk Slovak
sl Slovenian
so Somali
es Spanish
es-419 Spanish (Latin American)
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
tt Tatar
te Telugu
th Thai
ti Tigrinya
to Tonga
lua Tshiluba
tum Tumbuka
tr Turkish
tk Turkmen
tw Twi
ug Uighur
uk Ukrainian
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
wo Wolof
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu
Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated: 1 00:00:00,179 --> 00:02:20,300 hello everyone my name is zura and I am the cotolic in this video we're going to build a full stack application with laravel rest API and react before we start building the project let's have a look at the demo when you open the website you have two possibilities to create new account or log in with existing account okay the registration is pretty straightforward you just need to provide name email and password on login we just provide the email and password I'm going to log in with an existing account and I'm inside the website as soon as you open the website you see the dashboard where you have the overall information about the latest survey how many questions that survey has how many answers that survey received when it was created or when when it has expired date what's its status as well we have possibility to edit the survey when we click on this we go on the survey edit page we have possible to change the title description image expire date make detective and of course manage questions add new question remove question add options to an existing question and so on so inside the question types we have the following types but the application code is so extensible that you can easily add new question types if you want inside there okay you set up your survey you give it all options what you need provide some descriptions for each question right here so these are all the test questions at the moment and then of course you just hit the save button to submit the survey but you also have this public link right here which opens that survey on a public URL which doesn't requires authentication and you can just copy that URL and put on some blogs or social media and others can take your survey so here's the survey information it's the expired date we have the title description image and then I'm going to choose like options pay attention that it will go in the dashboard that survey has six total answers at the moment okay so I'm gonna just complete that test survey at the moment with some test data here and just click submit okay whenever I hit the submit I get some kind of 2 00:02:20,660 --> 00:11:23,360 success page thanks for participating in a survey and if I go on the dashboard and just reload it now I see that I have eight answers I think I double clicked on this uh button okay I clicked it twice okay that's why we have the uh two a two more answers and right here we have the other information like common total surveys we have created What's the total answers we have received or what are the latest answers we have received if you can go in the surveys we see all the list of the surveys we have pagination as soon as the survey surveys are more than like page size like more than 10 then you're going to see pagination links right here and you can basically uh navigate between there and when we click this create button you have possibility to create new survey okay it looks like a simple functionality but behind e there is a lot of work and a lot of struggle and if you are ready for such a work and struggle then you are welcome to this video in this tutorial you're gonna learn a lot you will learn how to build rest apis in laravel how to handle the authentication part how to create the single page applications with routing and State Management in react you're going to also learn how to create multiple layouts in your react application how to create scalable file in folder structure on lateral side you're going to learn how to build controllers request classes resources how to interact with modals how to work with the database and how to query the data to select the surveys or to select some kind of overall information for the user for the dashboard and more importantly at the end of this video we're going to deploy the project on custom domain the final version application will be deployed on reactsurveys.com which internally will connect to the API react survey dot com so you will learn how to set up a virtual private server how to install Apache MySQL PHP how to configure virtual hosts how to set up and node.js how to install let's encrypt certificates and the whole package from start to finish I think this is the perfect project if you want to sharpen up your laravel or react skills and learn how to build the application from start to finish including deployment it took a lot of time to work on this project and make it finally finished so if you find this video helpful don't be lazy and click the like button because that really helps me and you are supporting the channel before we proceed quick message from our sponsor hostinger hostinger is one of the best hosting platforms out there I have been using hostinger services for about past two three years even before we became partners and I can honestly say that their services are really amazing their servers are pretty powerful and their hosting your age panel is very very intuitive and very user friendly so that you can easily navigate and you can easily do everything what you want their prices are really affordable so if you go in the hosting web hosting which offers their shared hosting and I do have couple of videos where I deploy lateral projects on shared hosting you can find out how easy it is to deploy laravel on shared hosting and for just three dollar per month they offer a lot of services like 100 websites 100 gigabyte SSD storage you have free emails you have unlimited databases unlimited SSL certificates and you have possibility to uh you have also git support so here's the git support SSH access support and you have much much much more other things but you have also free domain under that web hosting three dollar per month I actually have couple of videos where I deploy lateral projects on shared hosting and it works quite amazing but for VPS hosting you can have a look their servers are pretty powerful compared to their price for just six dollar you get two gigabyte RAM 40 gigabyte SSD storage and like a weekly big cops and dedicated API IP address and like the latest uh operating systems as well and everything is really cool okay if you decide to go with a hostinger and grab the VPS hosting click add to cart which will open its checkout page right here you choose the period the same thing happens when you choose a premium shared hosting you choose a period the longer period you choose more saving you're making okay then you scroll down below create an account and right here you can use coupon code the code holic okay make sure you use the coupon code because that's going to give you an additional 10 discount and that's going to be also beneficial for the channel so by providing coupon code right here you get the discount but Channel you support the channel as well so click right here and now pay attention so your are just paying 258 dollar for four year server and if you choose like a shared hosting you get even more discount so I think that's a pretty good deal and when you create an account and click the submit secure payment you will be redirected to hostinger hpinel and then we can continue from there now let's start building this awesome full stack application with laravel react and Talon CSS for this we might need free prerequisite tools first we need composer we will need node.js because we will need npm to install packages for react and we will need also to run the fight server using npm and if you don't have your PHP working environment setup please check the following website apachefriends.org download example install that includes PHP mariadb and Apache web server if you don't know how to set up pH working environment just check my one of my videos I have a full setup for that all right and of course you need editor I'm going to use vs code today for this project now let's create a laravel project and for this I'm going to open CMD and let's navigate to the folder basically in which I want to create my project and that is under htdocs folder so I'm going to copy the path go to CMD CD and the path and right here I'm going to create my larval project I'm going to run laravel first of all um there are a few options basically to install lateral project one of them is to run composer create project and second one is to install a laravel installer for this we're going to run composer Global require laravel slash installer and this will install laravel installer and after this we will be able to create laravel projects with just running laravel comment I already have that laravel installer just I had a slightly older version so it actually updated now let's clear up what we need okay and let's run laravel new and right here I'm going to specify the folder name okay I'm going to call my project laravel Dash react Dash survey all right let's hit the enter it's going to take few seconds and I'm going to pause the recording all right the project was successfully installed now let's open the folder using vs code lateral react survey right click and open with vs code and here it is okay now I'm going to open Terminal I'm going to use git bash in this case gitbash terminal and I'm going to start the Artisan server PHP Artisan surf and let's open Now browser and type localhost 40 000 and let's close all the other tabs and we have laravel application up and running awesome now let's create database actually I have a plane and I want to follow this plan let me show this plan to you oops he here's my plan okay if we start from the scratch so we need to create lateral project create mySQL database so you can pause right now and have a look all the plans we're going to do in this video and we're going to of course follow it step by step okay so I'm going to follow I'm going to at least try to follow this point now let's open phpmyadmin and create database slash PHP my admin 3 00:11:23,820 --> 00:11:31,920 oops I don't have exam running so let's click and open example 4 00:11:32,760 --> 00:11:36,440 okay here it is 5 00:11:36,959 --> 00:11:42,600 and I'm going to start now Apache and MySQL 6 00:11:43,320 --> 00:13:50,660 let's wait a few seconds and here we have now let's create laravel lateral react survey database okay I'm going to click right here and call my database laravel underscore react survey 2. I already have a lot of a lot of react survey so I'm going to call this uh two and then let's choose encoding uh utf-18 before Unicode CI and click create all right we have the database created now let's open our project and I'm going to open Dot en file and configure the database right here the connection is MySQL the host is this the port is correct the database is this and we have the username and password and now we can run a migration so I'm going to stop the server and run PHP Artisan migrate hit the enter okay migrations have been applied let's start the server again and we have our project set up correctly we cannot test right now if the database is actually uh working if the connection to the database is fine but we can see if the tables have been created in this schema so let's click right here and we see we see the following tables have been created all right now let's create a react project and I'm going to start now and create a new terminal and I'm going to use white to create new react project if you want to see like full details how you can create new projects using white you can just check the invite documentation it's a Next Generation front-end tool and why it works much faster than create react app for example and it's really fast and really handy to create applications with white so I'm going to create a application with a white in my new terminal I'm going to run npm create write it latest and let's hit the enter 7 00:13:51,060 --> 00:21:43,760 let's agree on this the project name I'm going to call this react and now we need to choose the framework whether we want vanilla JavaScript vue.js react uh preact or some other things so wear and choose react and now it asks whether we want to use JavaScript or typescript I'm going to choose JavaScript right here and the application is created now let's navigate into react folder and we're going to run npm install and then we're going to run npm run Dev now let's run npm run Dev and the application is up and running by default it starts on the following Port so I'm going to copy the URL or just click on the URL and it's going to open in my second window so let me copy the URL and open this right here okay so we here we have the application running let me zoom out slightly okay I don't want to it to run on the following Port so I'm going to make few change right here let's open Package Json under the react folder let's close the envy and let's open picky Json from here and on this Dev script I'm going to specify right here dash dash Port equals three thousand so we save this stop the server and rerun it and now in the browser this one will not work anymore we need to specify Port 3000 here and we have the application running and we just click on this calendar and it increases so we have react application successfully really created now let's have a look at the react project structure okay inside the react folder we have this Source folder which contains all the projects and we have this main.js which is the main file which creates the react application and right here we it uses the up component which is the main component inside the up component we have this following counter and basically whatever we see right here comes from the app component okay and we have assets which just contains an SVG file and of course we have the CSS for the app component as well as the index CSS which is the main CSS I'm going to clean up my application I don't want the following CSS as well as I don't need these up CSS and inside this up.js component I'm going to also basically remove everything and just leave um up j6 okay let's just print like this and let's remove this react logo as well and let's remove this state as well we don't need them at the moment and this react SVG we can even delete this okay awesome now if we uh save all the files and have a look in the browser we just see this app and jsx okay so we clean up the project now let's install Halloween CSS for this I'm going to search for I'll go to the Talon CSS documentation or just in the Google let's just type Halloween CSS react and let's click on the very first the link let's go back and right here we need to create uh we actually already have created but we need to install the title on CSS all CSS and auto prefixer okay so I'm going to copy the following line and open the terminal this is the this is my react application terminal okay right here I have react running in my second terminal I have a lot of artisan running okay I'm going to create another terminal and right here make sure you go in the react folder okay and right here in the react folder we're gonna paste the following command and hit the enter when this is done we're going to run the following command which will create Talon CSS config file as well as the post CSS config file okay this is done I'm going to paste this and hit the enter from the react folder remember this okay now we have this Talon CSS config file CJs file these are the latest version basically creates CJs file previously it was creating just JS file and right here inside the content we have to specify all the file extensions we want the Talon CSS to care about okay and we have the content right here from the documentation so I'm just gonna copy this don't want to type all the extensions uh the indentation basically is set to four spaces which is something I don't like so I'm going to quickly open editor config of the lateral application and right here quickly add the following extensions so basically for every JS and jsx as well as CJs okay I want to set indent size to be two quickly save this I'll come right here and let's format the code and whenever I hit the tab pay attention now it indents with the two spaces okay so far so good now let's go to the documentation again we need to put the following directives in the index CSS so let's open index CSS and paste this right here let's scroll down below and we can already start the server but we don't need to run npm run start we need to run npm run Dem and in fact we already have npm run Dev running here's our application now let's use some Talon CSS classes so let's open up j6 and right here let's change this into BG purple five hybrid okay let's save this and have a look in the browser I think it doesn't work because we need to restart this server so right here we have this fight server running I'm going to stop it with Ctrl and c and run npm run Dev now let's have a look in the browser we just reload the page and we see background color now is purple awesome this is already good start now I'm going to install hero icons as well because I'm going to use hero icons Hero icons.com Let's go right here and right here we can search all the icons that is available but I'm going to click on the documentation link right here there are almost 300 icons let's scroll down below I want to find the installation instructions right here we have this npm Install hero icons slash react this is what we need to install so I'm going to copy the following command open vs code the third terminal clear up everything paste and hit the enter this will insult hero icons and we will already be able to use in our application let's actually have a look what icons are available right here we have a browse the full list of Icon names let's click on this open new tab wait for a few seconds and right here we have all the icons okay if you want to see how they look like uh visually let's go on the heroicons.com and let's type user for example and we have the following variations of the user okay and if we search the user right here we will see the corresponding names for how we can basically use these in the react application okay we're going to see this in an actual project let's close them we already installed hero icons and by the way let's test if that actually works fine so right here let's use user icon and that must be imported automatically okay let's try 8 00:21:44,280 --> 00:23:36,080 okay if it's not imported automatically let's let's first restart the server so I'm going to stop the server and rerun P npm run Dev okay this is the first step and then let's try again to use user icon no it's not imported automatically okay we can import it manually and when we are about to import this manually we can have a look again right here in the documentation we need to import from the following package hero icons slash react and then we have options for solid icons or outline icons okay so let me actually copy the following line and put this right here and we can use now this Baker icon and let's specify class name W4 let's save this and have a look in the browser and here we see this icon okay the icons are actually successfully installed now I'm going to create a login form for this I'm going to go to the taloman CSS page and right here we have components so I'm going to click on the components and scroll down below and we have a couple of free and paid components okay I want to find the login form let's click on show more right here and let's search for just form Maybe and where are the forms let's actually search for login maybe that's more relevant or sign up no there are no such forms uh why do don't we have those let's find the login form I'm sure it is somewhere right here 9 00:23:40,260 --> 00:26:10,940 here we see signing and registration okay I searched for a different name so this is the login form we are going to use and right here we have this code and this is free component we can use as much as we want uh for for any purpose basically for commercial or non-commercial and we have options for HTML reactant view I'm going to go to the react and then we can have a look at the code and we need to copy the following thing and let's now go in the app component and I'm going to replace everything with Ctrl a and delete and just replace and the component name let's change this into up however this HTML requires Talon CSS forms plugin okay without installing that plugin it's not going to look exactly as as it is shown on the website let's actually have a look in the browser okay so this is our form let's zoom out and this looks nice it's not bad but the input files are not looking exactly as it is right here especially if we have a look the Border width is something different okay so let's install the following plugin I'm going to copy the name and let's completely remove this comment and bring up the terminal open new terminal and let's run npm install Talon CSS forms it's going to take few seconds until this is installed here we go let's close this now we have this that installed and according to the documentation the example requires updating your template so on HTML we're going to do the we're going to add the following classes now let's go in the public and not public sorry we just need to open index.html and on this HTML tag let's add the following classes just like this I think I didn't copy it correctly and then we need to add H4 on body all right now let's save this and have a look in the browser okay this looks nice and if we just reload the page no I think we need to whenever we install something I think um we need to just restart the white server let me actually close this terminal and just stop the white server and restart it and now if you have a look 10 00:26:11,400 --> 00:28:07,400 oops I made a one mistake we need to open talances config and include these uh we're going to run require it Talon CSS forms so let's just save this and now here we go we have the form exactly as it is shown right here okay so that's fine I don't want to just like blindly copy and paste the HTML so let's open the app jsx and let's remove the comment from here and let's understand what is written so we have all tile and CSS classes if you are new to Talon CSS I recommend to check my 13 minutes very crash course it's going to give you the idea of Italian CSS okay but even I don't know these class names all class names by heart there's a documentation for this and whenever I need something I search inside the documentation but the idea is very simple we have class for one or two single properties and so here we have this flex and mean Age full so we have I'm gonna go through all the classes what is mentioned right here but we have an image which is the following image then we have the text which has a large um text 3XL and font bold and down below we have this link and then inputs okay and each input has a bunch of classes for styling and down below we have this remember me checkbox uh link and the button and Button as well has a bunch of classes and down below we have this lock closed icon that is hero hero like okay fine now let's scroll up and I'm going to make a one test let me change the HTML background into something like 200 not 20 and have a look 11 00:28:08,220 --> 00:29:12,679 okay we don't see I think this color let's change this into 300 and save it uh we don't see that for some reason no we actually do see that is the color changing maybe I don't notice this and then let me tell you why it doesn't update in the browser when we change the following HTML okay this happens because in the talmud config CJs we don't listen to the HTML extension okay and basically tolerances listens to the following extension files and whenever something changes it detects what classes we have inside and then compiles the final version okay if we update this file in it right here HTML file extension save this and have a look in the browser we might need to restart the server and now if we have a look in the browser 12 00:29:13,220 --> 00:34:03,600 no it does not work and the reason is because we don't have this index HTML inside the source we made quite a few mistakes right here okay let me actually move this down and I'm going to add new entry right here which will simply look at the index HTML okay and let's remove this from here so now I save this and here we go so here we have this background color by the way this color looks really nice but I'm gonna return this back into like a to 100 maybe here we go okay let's return this back into 50 or 100 I think that looks also really nice we're gonna work on this form and map this on the corresponding URL slash login and for this we will need react rotor let's now open vs code bring up the terminal I'm going to stop the server and I'm going to install a react rotor done a react Dash rotor Dash done let's hit the enter and we're going to create a rotor file as well okay there are multiple ways to create and configure roads in react I prefer prefer to create a dedicated file for the rotor so in the source folder I'm going to create a rotor Dot and jsx file and right here I'm going to create a rotor by by basically calling the following method create create browser router okay and the the following function should be imported okay and right here I'm going to pass roles okay I can create separate variable for roads and pass it right here but I prefer to pass an array directly const rotor equals create browser router and down below we're gonna export default router okay now right here we can already configure our roads so we're going to pass an object right here and we're going to specify path to be slash for example and we we're going to specify element to be let's specify right here up to be our element for path slash so we have our router created we are exporting from this file now let's open main.js and right here we need to import our route so import rotor from rotor dot j6 let's specify this as well and we need to also import rotor provider and we need to use this router provider right here instead of up let me actually delete this app and start writing rotor provider and that was automatically imported by vs code and right here we're going to specify router corresponds to the imported router now if I save this and have a look in the browser we have the exact same result okay but I think because we haven't run the server npm brand Dev and just reload the page and we have the exact same result why because we configured the router and we give this road router provider to use the following router and inside this rotor we have mapped slash into up if I just change this into up save this and have a look we see not found error okay because we don't have any kind of element mapped to the Slash Road but if we access up we're going to see the following page now I'm going to create four roles we're going to create actually if we have a look at the plane so we have so we have to create a dashboard surveys logging and sign up and then we're going to go to the layouts and create those layouts all right so let me open the rotor and let's define slash well actually we need to create also components so inside the source folder I'm going to create a views folder and inside views I'm going to define components let me actually create a dashboard.jsx component and let's generate a functional component and this is called dashboard we can remove this and let's actually create right here surveys the A6 awesome let's remove this let's create a login.jsx 13 00:34:05,159 --> 00:34:11,119 and sign up j6 14 00:34:12,419 --> 00:35:04,099 okay so let's remove this from login as well now if we go in the rotor and let's define slash let's map this slash into dashboard component and let's duplicate this three more times and this one should be mapped on surveys and we're going to use service component logging obviously will be met will be mapped on login and sign up will be mapped on sign up component and make sure all of them is imported right here okay let's check this sign up to have the correct name I think everything looks good 15 00:35:05,280 --> 00:35:44,060 yeah I think we don't have any any kind of name why is this one underlines right here not sure a known word okay I see now if I save this and have a look in the browser app doesn't work anymore it shows not found if we access slash we will see dashboard if we access surveys we will see surveys let's check login and sign up as well okay all of them works and if we now go in the app.jsx and copy everything and go in the login and paste and just change the app into login 16 00:35:44,520 --> 00:37:36,240 and let's check now login here's our login page okay and we don't need app component anymore so I'm going to delete this and CSS as well okay now we're going to create sign up as well and basically sign up will be very similar to login so I'm going to copy everything from login and paste inside sign up let's change the component name into sign up and let's quickly change right here into sign up for free just to make a differentiation between sign up and login let's open the browser and we have an error we are using up inside main.js so I think we need to remove it okay and we are using App inside router as well let's remove it from here as well okay now we have login and we have sign up okay sign up for free awesome but now let's understand so we are using the same layout exact same layout so we have an image right here as well as the outer div elements and this one is the same for both and in the future if we add like a forgot password page it's going to have the same layout so in an actual applications we need to Define reusable layouts and the layouts will be used for many pages in this case we will Define two layouts one for will be for the guest users that's going to be for login and sign up and second will be the main layout default layout let's go now in the source and I'm going to create a components folder components and inside components I'm going to create guest layout.jsx 17 00:37:36,960 --> 00:41:23,359 and let me quickly Define also default layout.jsx we will need in the future in the guest layout let's generate the functional component and right here we need to Define few things um but before I write anything here it will be more logical if we go in the rotor and Define the uh use this get layout right here okay so I'm going to take out this login and sign up and instead of them I'm going to create uh Slash let's call this let's put a let's put alt maybe or just let's leave it slash okay uh for this slash we're going to use element to be guest layout and that must be imported that was actually imported I think right here okay this is the element we're going to use for this slash but we need to Define children okay and inside children we need this login and sign up okay whenever the user tries to access slash login or sign up and by the way if we put right here something like guest then the actual URL will be um uh just uh if we remove right here slashes the actual URL will be guest logging and guest sign up in this case okay we can test this but if we open this case layout we need to Define rate here Outlet okay the outlet is the place inside which the child element will be rendered in this case login or sign up in this case the guest layout is absolutely empty but if you just write text right here part of a layout let's save this and let's open browser and now our sign up URL basically doesn't work but if we specify right here guest slash sign up this works and we have part of layout right here let's access now login we have part of layout uses on both places if we open rotor and put slashes right here Let's test this now this doesn't work anymore okay we need to access with Slash login or it actually doesn't even work like this so we just remove Slash from here and now uh we just leave slash right here and now we have login and sign up okay this looks good let's actually go in the login and I'm going to take out the whole component and put this in the guest layout okay and then we're going to find where the outlet will go I'm going to paste this and let's understand what is the part of the layout and what must be the part of the login for so we can leave this image inside the layout and then we have this H2 signed into your account which is obviously part of the component itself we have the following so this is part of the component obviously but this part of the following div as well so we can't actually take out the following part so let me actually move this out from the following div element and put this down okay and it's going to work very nice if we just um let's save this and if we just go to the slash login lock closed icon is not defined that's something we can take on from here and use it in the guest layout 18 00:41:24,300 --> 00:45:45,980 save it and this is now guest layout and well basically right here we see login form but as I mentioned this is guest layout okay everything comes from here and now let's take the following part including the form itself and this is the guest layout and now let's go and log in and put this right here okay we save this and let's go in the guest layout and this is the place we need to output and create Outlet now our closed icon that basically still should be in the login form okay let's copy this log code I shouldn't have copied that so let's put this right here my mistake sorry so now we have this nice login form and we have a layout just put in one place now if I go in the sign up let me close other components and collapse the left side so let's close the everything else so we have a sign up and inside the sign up we only need the form and the following h2n paragraph so let's put them together and everything above can be removed and everything below the form can be removed so I save this and if we go in sign up this is how it looks like now I go in the guest layout and I want to change something for example I want to give this one BG slate 800 for example okay this is the background and if we go in the login that was changed for both okay this is obviously the advantage of using layouts I don't want this late background right here okay looks awesome now in the same way I'm going to Define dashboard layout I'm going to open the components section right here let's go back and let's search for layouts and we have different layout options but all of them are basically locked except the following one which is stacked layout inside there there are nine components but the first one is free others are also unlocked okay so that's fine I really like the following layout so let's switch to react right here go to the code and we can have a look uh what is the actual source code but I'm going to click copy and now let's go in our application let's open uh default layout and let's paste everything let's move up uh let's change the component name into default layout this requires HTML and body to have the following classes we have those classes on HTML and body and now I save this and now let's open a router and configure roles for the default layout in the same way so I'm going to create right here path corresponds to slash we need element to be default layout and inside there we will need children roots and let's paste it okay so let's put comma and format the code okay this looks nice now if I save this and go in the browser and access whatever so we have failed to result import okay inside default layouts it failed to import LS UI react I think that is because let's go in the default layout that is because the Headless UI was changed okay and we want to import them from 24 maybe solid folder so if I save this 19 00:45:46,680 --> 00:49:00,140 disclosure menu transition oh my bad I thought the error was about hero icon so headless UI yeah this is something we haven't installed and what is headless UI let's search for headless UI this is react this is basically a JavaScript components react or vanilla JavaScript or um or vue.js which doesn't contain any kind of styling okay and I think they only have a reactant view not vanilla JavaScript and they have drop downs and select boxes and maybe tabs and models basically anything great that requires JavaScript functionality but they are not tied to any kind of CSS framework the examples right here are based on Talon CSS but if we have a look at the code the code basically gives you possibility to add any kind of CSS framework you want okay inside the Headless UI it doesn't have a built-in classes CSS classes and what we are interested and what we are using is drop downs so if we just copy the following thing headless UI react and install that so I'm going to stop the server run npm install Atlas UI react and then we then we're going to rerun the server npm run Dev and now let's have a look in the browser uh oops I think we shouldn't have added the this right here okay I thought that was hero icons my mistake so now let's just reload the page and have a look so this is login now let's access slash which should be the dashboard and here we see the dashboard okay now let's access surveys in this service page of course they are identical because we don't use Outlet inside the default layout but the layout is there and layout is implemented okay and now we can start working on to clean up the following layout add right here dashboard and surveys and maybe remove this notification and adjust it exactly as we need foreign now let's open this code and find the place where we need to put the outlet this is the first thing down below we have somewhere right here replace with your content okay this is the place where we need our content and I'm going to post right right here Outlet okay this is for my content I save this and here we see surveys and if we just access slash here we see dashboard but we want the title to goes right to go right here okay so let me actually put Outlet right here okay and I'm going to take this out and open now dashboard and replace it but we have two elements so we're going to create fragment 20 00:49:00,480 --> 00:50:18,319 save this and let's open surveys and do the same thing right here okay let's give this one title surveys this one is dashboard and in the default layout we don't need to do anything we just save it and this is dashboard and this is service oops I made a typo service here we see it this looks this looks exactly as we want now let's go in the default layout and clean up this component a little bit okay so we have the user information which is dummy information at the moment we're going to take out the user information from the backend the name and email the image URL is something we are not going to use we don't have that and we are not going to implement so we can just put right right there um like maybe talwind um sorry yeah hero icons icon and yeah for the dashboard let's give it let's change this href into two and I'm going to specify right here the um the actual Road in this case it's going to be dashboard 21 00:50:19,140 --> 00:50:48,119 by the way I think we don't have dashboard do we no this is that this um throws 404 if we go in the rotor and we can quickly do that so basically uh we can put this inside inside default layout or or it really doesn't matter so I'm going to Define right here whenever we try to access slash I want to navigate 22 00:50:48,599 --> 00:50:51,599 into 23 00:50:53,119 --> 00:51:14,700 into slash okay this is um not slash sorry dashboard and then right here we need to configure dashboard maybe two times okay let's duplicate this dashboard and 24 00:51:15,599 --> 00:54:48,020 well I think we can put this right here okay this is probably what how we should have so whenever we try to access slash we will be redirected to the dashboard and on dashboard uh we basically handle the following maybe the beta will be if we do it vice versa so whenever we try to access dashboard we will be navigate to the Slash and we handle slash okay let's put comma right here now if we try to access slash dashboard it will redirect us to slash and on slash we render the following component all right now if we go in the default layout I'm going to change this into slash let's remove this we don't need that and right here we need surveys two that's going to be slash surveys and let's remove current as well projects calendar and reports can be removed inside the user navigation we can remove your profile in settings we can only leave sign out however we probably even don't need that we can put sign out right there without iterating over the user navigation menu items and we have this dashboard and surveys so however clicking on them doesn't do anything because we need to take care of this now let's scroll down below and find the place here's the place where we iterate over navigation menu items and have a text right here we're going to change this a tag into nav link this is the um this is the component which is imported from the react rotor done okay so scroll down below so here we have it we need key I think we can leave this key however we're going to change href into two and two right here as well however inside the class name okay so we are using right here class names of function which basically takes multiple classes and the filters them and joins with space however we need to separate here function because we need to also detect if the current road is the active road or not so let's accept right here function and we're going to return the class names okay at least now link basically accepts inside class name pass is also function and right here we're going to get an object and if we destructure this object we will have is active okay and we can use this is active right here instead of item current I'm going to use is active okay and we can of course put is active right here but I think we don't have access exactly because that is only available for a class name so for Simplicity let's just remove this area current and we have a typo right here nav link all right I think this looks this looks correct now if I save this and have a look in the browser we see dashboard is active if I click on service now service is active okay we have implemented activating and we need to do something similar for the for the mobile version scroll down below 25 00:54:48,540 --> 00:55:22,339 here we see the navigation okay so let's actually change this into um now a link and key let's remove this right here and here we need two we're going to accept Arrow function the structury takeout is active and we're going to use is active right here and let's just remove it okay now let's have a look on small screen 26 00:55:23,099 --> 00:55:50,841 dashboard service okay they are active exactly as as expected okay now let's take care of the right side so let's start from the top let's move we have the button which is the Bell icon button so we're going to remove it we don't need these notifications we don't have this on desktop let's check on mobile - we have this still right here let's - scroll down below 27 00:55:51,300 --> 00:56:20,119 um where is the Bell icon right here so we can remove the following Button as well okay the button was removed the user information we can leave this at the moment because we can change it whenever we implement the user authentication with the server side however let's take care about the layout sorry side note 28 00:56:21,540 --> 00:57:32,880 let's search for a search for where we use this user navigation so I'm going to search for this and right here we iterate over user navigation but we don't need iterate because we only have one menu item so let's just remove this and this is menu item which by the way we can either link use a naval link right here and redirect to the specific or we can just leave these as it is but we need to add an event click event listener for that okay let me actually remove the following thing and let's just leave a element inside href um we just put um maybe a hashtag but we need on click at the moment uh we just call a function let's put except right here an event and let's just call log out and pass the following event at the top we need to create that function so right here let's just create const logout 29 00:57:33,300 --> 00:57:53,839 like these we're going to call prevent and default oops default and just console log out okay let's scroll down below where we we're 30 00:57:54,900 --> 00:58:00,800 where was that that was 31 00:58:02,579 --> 00:58:18,140 let's search for sign out maybe or let's search for user navigation I think we don't use user navigation I think I got a little bit lost okay here's it 32 00:58:18,720 --> 00:58:48,260 and let's format the code and I think this okay we don't need key and we don't need this we just write sine out and we don't need I think active as well we just leave the following classes we don't probably even need this function 33 00:58:52,380 --> 00:59:47,000 okay I think this is correct now let's have a look this is sign out when we click on it uh let's go in the console we see logout right here okay let's just reload the page make sure we don't have any errors and let's test sign out again so we get the log out so on desktop we have it implemented correctly now let's take here on the mobile when we click on this um nothing really happens so let's scroll down below we can do something similar so I'm going to copy the following code scroll down below we have this navigation and down below we have the user navigation okay this is something we need to replace let's delete the user navigation we have the disclosure button uh which is is a 34 00:59:47,280 --> 00:59:51,740 and let's add right here on click 35 00:59:52,260 --> 01:00:02,900 on click uh we accept event and called log out passing this event 36 01:00:03,420 --> 01:03:59,160 uh we can remove the key and inside href we can specify again hashtag for the class names but we can leave as it is for the sign out we just write sign out now I save this and just reload the page make sure we don't have any errors and click sign out and we see it will go right here okay so we have called the method what what we want on logout in both versions desktop and mobile okay I think we have finished working on the layout now we have a layout but if we observe dashboard and surveys they still look very similar okay we can put the following content in the layout and then make adjustments so that we have a title and the main content right here so by the way there's the place of the content so surveys content okay so we have two places we want in the um General layout surveys right here which is the title and the content and something similar is for the dashboard that is dashboard content okay so how we're going to do that I'm going to create a page component if we go into components and Define page component oops that should have an extension j6 jsx and let's create a component sorry RFC okay this is the page component inside this page component I'm going to accept prompts and we will need Title I'm going to also accept like buttons which by default can be an empty string and I'm going to accept children okay and let's go in the surveys and copy everything and let's create fragment here paste this and this is the place for this is the place for title so let's just output title right here but we might need also buttons we will need these buttons definitely so this is the title in right here on the right side we might need buttons especially on the surveys page to create new survey so we're going to create a space for the button so we have right here H1 and next to the H1 I am going to Output given buttons okay however let's give this one class Flex for display Flex let's give it also a justify between and maybe items Center okay so this looks good where we have a title right here in the buttons If that is given it will be outputted here and down below we're going to Output all the children let's say this go in the dashboard and instead of all these now I'm going to use page component okay the page component has a title so we can specify this title let's by the way close this page component and this is children okay all kind of inner content and inside title we're going to have dashboard if we need buttons we will Define it as well now let's copy this go in the surveys and paste them right here and let's change this into surveys the title and this is surveys content 37 01:04:00,740 --> 01:06:43,099 helps this one I think I have everything is good inside the dashboard now page component is not defined that must be imported so I just delete the last letter hit the control and space and hit the enter right here okay that was imported T is missing right here perfect so here we have the surveys service content dashboard and children right here okay so we have defined reusable page component and if we just reload the page we don't have any errors on the right side now let's create a context and context provider and use inside the layout okay we will need user information to be displayed from the context so let's go in the project and I'm going to create a context provider actually in the source folder let's create contexts folder click on texts and inside there let's create context provider Dot js6 the lowercase all right here okay so we have this context provider now we need to create context const State context we can of course have multiple contacts but in this tutorial I'm just going to create one context uh context equals create context and that create context needs to be imported from the react okay the create context accepts a default value right here at the moment I'm just going to pass a name to the object but we're going to create couple of things right here and I'm going to explain why this is also necessary okay and down below we're going to export constant uh context provider and there's going to be an arrow function and from here we're going to return js6 component okay and it's going to be State context dot provider okay we created the context right here and now we are returning provider okay this provider inside right here we will need to pass children as well and we can take out Children right here and then output and the provider needs a value and we're going to specify right here value 38 01:06:43,559 --> 01:11:27,320 and we're gonna the value basically uh should be an object we're going to provide an object right here so we will need an object and finally it turns out to have a double curly braces but actually the first one the outer one is for react and this one indicates that this is an object okay and down below we will need few States okay now I'm going to use a state const let's define few state for like a current user and we will need Set current user as well use a state and by default the current user will be an empty object okay the second state we will need is the user token and let's create right here set user token and we use State and by default let's specify null okay and then down below let's pass right here current user uh let's pass Set current user and we need user token as well as set user token okay so we have these ready and finally for Simplicity I'm going to create export const use State context to be a function which will return use context of State context okay we can write use context State context in our components as well whenever we need them but we just create a handy function from here use State context so we have now this uh the context provider ready however now let's go in the dashboard layout for example uh sorry uh default layout and let's say we want to use the current user information instead of instead of this user and we can remove this user navigation by the way okay instead of this user I want to use a current user information okay I'm just going to actually delete or comment out this user and this will cause errors in the component but we're going to fix that so basically I want to use now use State provider how did we call it use State context sorry use State context and we can assign this into State this is our our state but let me actually destructure this state and take out current user from here and pay attention now I want outer completion to work but when I start typing current user VSCO doesn't autocomplete that however if I go in the context provider and when I create context if I just provide an empty values like I have a current user which by default is an empty object I have user token by default to be now and I can also specify Set current user which by default is an empty function and just like this and let's specify set user token as well to be an empty function now if I go in the component and just try typing right here current user it autocompletes okay I need current user information in the current user information something which I want to Output in the default layout in the place where we have this user information now where is that let's search for user and this is it okay the user let's actually change this into current user and for the image we don't have actually an image and we're going to use user icon user icon and now let's pay attention the user icon was imported from hero icons react 24 outline okay now we have two second place as well for the user 39 01:11:28,020 --> 01:13:33,860 here it is so let's remove these image and let's create user icon here however we might need to add a few CSS classes talances classes and what else do we have so do we have user as a word as a lowercase and word somewhere like this one okay I think we don't have this user anywhere we are using current user if we go in the context provider and right here when we create the current user state if I just provide the following information now let me comment this out and I need this part and let me actually delete this so paste this right here save that and now let's have a look a user is not defined okay if I just reload the page the error basically disappears and now let's have a look so the user icon is not available by the way uh this is something we need to we need to quickly fix so if we go in the default layout scroll down below we have the user icon let's give this one W maybe eight okay here we see and let's give it also text white Maybe that's too much probably let's give it W6 let's give it also hate 6 and BG Blake slash like a 25 Maybe and let's give it also adding off maybe two and rounded rounded full well it's too small let's increase it into eight 40 01:13:34,320 --> 01:14:00,440 okay that's not ideal but it's like it's kind of indicator that this is a user icon okay and uh I want to see the user information so we don't have the user information the current user information and I'm trying to answer now why if I scroll down below we should have 41 01:14:01,080 --> 01:16:22,562 here we have the current user okay and the current user has name and email yeah I missed one very very important thing so we created the context provider but we don't use this context provider so we're going to use main.js and right here we need to Define context provider okay and the context provider needs to be a parent element of the router provider so I save this and now let's have a look so here we see Tom Cook the email which comes from the context provider and if we go in the default layout we can also use the user icon let's search for the user icon above take the following component and replace it right here okay I format the code we see user icon here and the user icon here as well so we have created the context provider right now and we are using that so if we go in the context provider and for example set the default value for token as well and set this into 134 and this is the user token and go in the default layout and use this right here user token and then I can print out the user token somewhere right here maybe user token so here we see these one two three four okay so we have successfully successfully created context provider now let's make dashboard and service page to be protected page let me close everything except the dashboard and actually let's close this I want default layout because default layout is the layout that is only that should be only available for the authorized users so right here basically anywhere above return I'm going to write if the user token does not exist - okay at the moment we're gonna return - navigate 42 01:16:23,360 --> 01:26:22,860 to login okay so this is what we are going to do and let's open now context provider as well and change the token to be an empty string for example if I save this now and open the browser we're on the login page if I try to access slash or try to access surveys I am not able to do this okay because right here we are redirecting to the login page if I go in the context provider and set some value right here and open the browser and try to access slash dashboard now I am able to access the dashboard or even surveys that's fine now this basically means that right now it's a simulation that the user is authorized the token exists okay it's a simulation that right now the user is authorized and we need a like a defense simulation as well that if the user is not authorized basically if the user is already authorized and tries to access a login page so right now I am authorized okay and that's why I am able to access surveys and dashboard but if I try to access a login page I should not be able to access because I am actually authorized so now I have to open guest layout and right here I'm going to do the opposite so first let's use the state uh from the default layout let's copy this go in this layout is so we have the user token and by the way this use State context needs to be imported so here it is and let's write an if statement if user token exists we are going to return navigates into slash okay so whenever token exists and we try to access guest layout we should be redirected to the dashboard and we are on the dashboard if I try to access login slash logging oops it should be three thousand we are on the dashboard if I try to access slash sign up we are on the dashboard okay so just like this we have created protected rows I just remove it and now we are on the login page now let's start working on the surveys page on which we're going to render all the surveys and at the moment because we don't have backend ready yet we're going to define the dummy service Json data and let's now open the context provider and right here let me create a variable for TMP service like for temporary storage at the moment because finally of course we're going to get the information from the backend okay I'm going to call this TMP surveys and it's going to be obviously an array of surveys and I'm going to quickly copy and paste a single survey Json I'm going to put the link of this Json in the video description as well so that you can just grab the Json and paste in your code at the moment okay and let's start from the very top and understand how the survey what is the structure of each individual survey okay so each survey has an ID obviously unique identifier image URL title slag status description created yet updated it expired date okay and each survey has questions and the question can be one of few types the question obviously has its own ID and type which is in this case text and the what is the actual question okay from which country you are in the description that's that's an optional additional information about the question okay down below we have the checkbox and the question and description however the checkbox might have additional options okay where user has to select one of the options for the options of options is obviously an array by the way right here the data itself is an object okay because except that we're having options inside the data the data might contain in the future some additional information such as required for example required flake so that gives us much more flexibility in the future if we decide to update and Aid required or a few other things in the data we have like a space for that next to the options we would be able to add additional additional properties okay inside options we have uid and text why did I choose uid because it's very simple to Generate random uh unique uids in browser rather than IDs okay then we have a few options each question might have a few options let's collapse the options and let's go to the second question we just select select looks very similar to checkbox it has data and options as well we have a radio which also looks very similar to select and checkbox it has its own options Down Below have a gain checkbox we have a text area in this case text area has data empty array or empty object it can be also empty object and text obviously okay so this is just one survey item so now let's implement the code correctly so that we take this TMP surveys by the way let me actually collapse this and right here I paint few more survey items that's gonna help us to have more data I added two more okay and just copied and pasted and we have the same TMP Service as I mentioned okay now let's put right here in this create context surveys which by default came in Array and down below we create States right here and let's create right here surveys and set surveys oops I have a typo surveys all right let's use State and we're going to pass right here TMP service but let me actually uh well let me think so I can directly pass team surveys it's not a problem but I was thinking maybe we just need to destructure the TMP surveys and just create new array um because we if we decide to modify TMP surveys now from the place where we will use that State uh it doesn't affect the original team service but in this case I think we don't care so let's just directly pass right here TM service okay and obviously finally we need to take that surveys and give it into State context provider let's give it surveys right here okay we don't need set service at the moment now let's open survey oops surveys dot jsx file and right here right here we can output our surveys let me now use const State equals State equals use context sorry use state uh how is it just forgot let's go in the dashboard or let's go in the context provider what is the method use State user yeah that is my mistake it should be use State context okay let's actually fix this small thing use State context and let's go in the surveys and call this use State context but that needs to be imported as well and or we have a state we can destructure the state and take out surveys right here okay and let's print actually what is these surveys however I think we're going to have an error first of all we don't see anything I think because we have an error let's just reload the page and let's observe so yeah user State context that comes from the default layout I expected that so if you go in the default layout we are calling method user State context that is a typo right here we need use State context and let's fix the import as well right here now we're good and if we just reload the page uh do we have it yeah we have this in the guest layout as well let's open guest layout uh okay we don't need current user right here but we need state so let me actually fix this however we can just delete this current here we aren't using it now let's again have a look okay now we are in the login page which is good now let's open context provider and set something in the token okay imagine that like we are simulating that we have already talking in customers authorized so we are on the dashboard page page right now let's now go in the surveys page and right here we're going to see the date okay this is our service data and now we can start iterating and render those surveys uh let's open service component and let's actually let's format the code okay we don't want formatting and right here in the inside the page component I'm going to start iterating over my surveys so uh surveys.map 43 01:26:24,719 --> 01:34:27,860 we have uh right here survey and we're going to return um let's actually imagine that we already have a survey list item because I want to create a like a separate dedicated component for each survey item so let's let's go actually in the components why why should we imagine let's go in the components and let's create survey list item.j6 it should be camel case naming is it yeah it is I think okay now let's go in the survey j6 and let's use survey list by the way I think I haven't written anything there let's just rename this into js6 jsx hit the enter open and generate functional component and the name is correct okay we have it ready now let's try to use it right here okay here we go so that was imported right here and let's now accept inside survey list item component let's accept a survey so let's accept props and we're going to take out survey right here and I'm going to accept right here key as well that's going to be the unique identifier okay and okay we don't let's leave it everything as as it is right now and let's make these surveys component ready okay so we're going to pass right here survey that's going to be our survey and we are going to pass also key and the key will be survey.ib that's going to be the unique identifier okay and I want to wrap everything in a div okay let's move this down and the Steve needs to have a couple of thousand CSS classes okay I'm going to copy and paste the classes right here greet grid calls one so on the mobile screen we show just one and above small screens we show two and above medium we show three okay this looks good now let's have a look so here we see three survey list items and if we remove the right side we're going to see them in the same line in the same horizontal line okay let's just reload the page we have an error right here several setting key is not a prop trying to access it with the result in the end Define okay okay let's check in the code what did I made incorrectly if we go in the uh we're passing right here key which should be passed in the server list item yeah my bet is that we shouldn't accept key why did I do that I don't know so the key is something which needs to be given to the component it's a predefined text pretty fine key basically that we need to give a component and that key is necessary whenever the virtual dump updates it needs to know where where the exact component is so basically we need to give this key right here and there is no necessity to accept it so if I just save this and just reload the page we won't see any errors right here okay now let's go in this survey survey list item and work right here well let me actually remove the Steve and I'm going to create a new component first of all let's create outer wrapper HTML element div and we're going to give a couple of tolerances classes to this like Flex and flex column and padding and Shadow and background white let me collapse the left side and it's going to have also fixed hate okay then we're going to Define an image with a source and ALT we're going to also give it a class name it's going to have a full width and fixed height and object cover and down below we will need the survey title and Survey description so pay attention right here we have a dangerously set in our HTML so whatever is the survey description we assume it's a safe HTML and we just render them as an HTML not as a text for this we will use the following property dangerously set inner HTML and we're going to pass right here an object which should have a underscore underscore HTML corresponds to some kind of HTML okay and we're giving it also overflow hidden Flex one and let's continue and down below will we I want to create um like a footer of the survey item which will have a like an edit button and some few other buttons okay so the first button is an edit button okay what is this t button component so the t button component basically does not exist yet but I assume that it already is created and exists which we will create in a few a few minutes basically but this t button is stands for in my opinion like tallowing button okay this is how I named it and the talent button will have a different variations and colors and different styles okay we are going to create a very reusable t button component which will have a different variations and we'll be able to use that core button component in our application in any place where we will need that okay it's going to be a good example of creating reusable react components it's going to have right here too and we're gonna map it to the following URL so this road again doesn't exist I think we haven't created that URL and that's going to be the survey update page and right here we are using hero icons pencil icon okay and we're going to create two more buttons one button will be for to view survey publicly as a guest user and for this we're gonna again use the t button but this t button has Circle and Link so Circle means that it's going to be like a full circle type of button and the link means that you it's not going to have any button Styles it will be just a link okay link type button and it's going to have also uh H ref right here which basically will open the following link um in um as a normal href not as a react Rod like we have it right here okay and again we are using right here heroicos Arrow top right on Square icon so we basically see how this looks like and then down below we are going to add also a delete button but we also check if the survey has ID then only in this case we create another t button which inside has a trash icon for delete purposes and we listen on click of the following on the following button and the Styles is circle a link and the color is red okay and just like this we have this survey list item almost ready we don't have on click right here which we we will uh we will create basically right now or we can even accept from here as a prop so let's try to accept it from here I think that's going to be more logical so we will accept on click and if we go in the surveys I'm going to pass on click corresponds to on click and I think we need to Define right here const on click equals an error function and let's simply write console log on on delete on delete click 44 01:34:28,500 --> 01:34:31,820 okay this is something 45 01:34:33,600 --> 02:00:44,159 and this is something we should not be called on click so the prop for survey list item for deleting if we wanted to put this in the service component that should not be probably called on click that should probably be either right here or we should accept on delete click okay that's more logical and I'm going to put on delete click right here and then inside the surveys we'll listen to on delete click and call on delete click and then right here this should be called undelete click as well and we print on delete click okay so everything now looks good except we don't have this t button component now let's go in the component section and basically I'm going to create a folder right here called core and inside core I'm going to create t button why did I call it a core because all the components which I have right here so far like a survey list item for example and a few others our maybe page component is also a core but the survey list item is more specific for a single page basically for surveys list page but whatever goes inside the core that's going to be like a very basic minimalistic components that will be available and should be used in the entire application in almost all the pages okay it's going to be very very basic and you can even copy and paste the core folder from this project into some other project now for example this t button Talent button and then you're going to have those components as well in any other project okay so now let's go in the t button and first generate the component and we have the correct name we don't need this import and let's delete everything and create this button first of all let's import a link component from the react rotor down okay then we're going to Define right here couple of props we need color prop because we're going to have different variations of the button and the color indicates what color of the button it is we have a two which is going to refer to the react rotor Dom wrote we have a Boolean property Circle true or false we have href link and target the target basically is more related to href okay if we have ahref then the target is either blank or self or something else okay now let's start working on the button itself in CSS classes by the way we're going to also separate here children which will be rendered inside each button okay let's start with the classes and we're going to have some basic classes like white space normal and text small and flex and Border okay but down below we're going to start writing a logic so if the link is true which means that it's a link type button not a normal button then we take those classes and create new classes and then put right here the transition colors okay and we start checking if the color is like Indigo for example we add text into 500 Nano Focus border Indigo 500 as well so if the color is red then we add different classes here okay so we have an else case which means if the link is false if the button is not linked type it's a normal button then we have right here text white and focus ring two and ring offset 2. okay and we start again checking if the color is indigo we add the following classes inside classes if the uh like a color is red we had the following classes if the color is green we have the following classes okay and down below we're going to also check if the circle is true then we will add the following classes so we basically have a fixed width and height on the button which has Circle true okay and in the else case we again take take the classes and give the following CSS classes okay padding zero horizontal padding vertical padding and a rounded MD I think we don't need this padding zero here um okay down below now we create a fragment inside the fragment so we check if the href is true we're going to create a element a tag okay which will have this href inside there it will have also the following class names basically we defined above and we don't join those classes because the classes array we don't join those classes and then we also give it a Target whatever is the given Target and inside the a tag we render children okay so the next case is if 2 is available then create a link component with the two and the class name will be again classes joined and the children will be inside the link okay and the third is if uh nor to neither href is available then we just create a normal button okay let's adjust a normal normal button which by the way we don't I think we don't use at the moment um which obviously has the classes and the children okay so this is how my like a basic t button component this which which I created in a few minutes basically uh but this t button can be also improved step by step like accepting an event listeners and um have a different color support Etc okay this is just a basic component but this gives you an idea how you can create your own reusable components with different props based on the different props okay so we have this t button and we if we go in the survey list item I think we need to use this t button right right here so I'm going to just delete the last line and last character of this t button and and then just hit the enter right here which will import this t button here and I think it is missing so if I just save this and now go in the browser t button is not defined on the surveys page let's go in the surveys and on the surveys we don't have t button and Survey list item we do have t button let's just reload the page okay now pencil icon is not defined that's clear let's just delete in and hit Ctrl and space and here's pencil icon which was imported from the um hero icons outline I think this one will not be also available so let's just import it he here we have that and the last one is trash icon let's just import this one as well okay here's trash icon now let's have a look in the browser we have let's just hit the F5 to reload and we have some good result okay so this is survey list page we have all the surveys and down below we have this edit button okay which which is our t button and we have this uh link to open in an external page and we have right here delete button which is in my opinion awesome so if I just inspect this and go in the console and hit delete right here nothing really happens at the moment but let's go in the surveys actually we need to go in the survey list item and this is the t button okay and right here we pass on click but we don't use this on click okay and this is something we need to add in this t button so if we go in the t button I'm going to accept right here on click which can be by the way um as a default like empty um empty function yeah it can be an empty function why not so let's just format the code I saved it let's scroll down below and right here I'm going to add on click which we'll call my prop on click I save this and now if I just click on this button on delete click is written in the console okay now we can handle this case and actually Implement deleting survey in the future obviously because at the moment we don't have actual surveys coming from the database now let's start working on the survey page survey view or create new survey page okay so we have this like it's a diamond data but we have this list ready which will connect to the back end a little bit later but let's create now survey creation page let's open now our rotor and we need to Define right here a new road for creating a new survey so I'm going to duplicate the following line and let's just call this surveys slash create and let's define now New View and I'm going to call this survey view jsx let's generate the component survey View and let's save actually actually we need to use right here page component that's good age component okay and we need to give it a title which will be create new survey okay and then we have right here um like a survey form let's just leave it um like this right now and now I'm going to open the router js6 and right here I'm going to now use the survey view element which should be imported okay so we have that imported surveys slash create now if I open the browser and well how can I access so let's just access survey slash create and then we're going to create a button for this as well okay so here we have create new survey and Survey form so let's just open developer tools just in case we have any errors no errors so far so that's perfect now let's go in the surveys and we're going to define a button so we have this page component and if I open page component we have like a prop buttons okay so I'm going to pass this prop now inside the page component let's create now buttons and the probe the idea right here is that the probe basically can be entire new component okay so let's use curly braces and inside there let me move this actually down it's going to be more readable inside there I'm going to return new js6 component and let me actually call this t button okay and it's going to be my button inside there I am going to use plus icon or maybe plus Circle icon from the outline folder okay we have that let's give it some talances classes like a hate of six maybe W 6 and margin right two and let's give this a text create new as well and what else do we need so let's give some color to this t button because by default I think it is an indigo so class class name or maybe we just give it a color equals green and we give it also two okay and the two will be surveys slash create now let's save these I think we are importing this t button which is fine and let's format the code and have a look if we go in the surveys page um we don't have any button right here but we should have it should be called I think buttons s is missing so now here we go so we have this create new button whenever I click this button it opens this create new survey form and let's now start working on the following form if we go now in the survey view this is the place inside which we're gonna work by the way let's just remove the react from here so let's you now create a state I'm going to create const survey State let's create survey and set survey use State inside a used State as a default value I'm going to pass the survey survey object okay and the survey object needs to have like a title and slag and status and description and Imogen URL and expired it in questions okay this is the basic survey State and now let's create let's create actual form let's create form tag first which will have an action method and on submit event listener okay inside there we will Define a div for some styling and inside there we're going to have additional div with some horizontal the vertical spacing background white and padding and so on and inside there we can already Define Fields so if you want to like know more about what options about the fields are available the input types I'm talking about the input types go to the entitlement components documentation okay so right here we have the as I mentioned we have a couple of free and - paid components and if we just search - for forms forms so there are definitely few form components maybe here here we have it form layouts okay and I took a few of the form input elements from here for example the image is taken from here and you have a different main different types of input fields and the layouts okay checkboxes and radios you can have a look at this to just understand few things better if you want but I think everything will be clear in this tutorial as well so we're going to Define an input field for image so which will have obviously a wrapper div element inside there we will have a label and the div element for the input itself inside there we basically first make a few like few checks so if the survey image URL exists which means that if we are updating the survey okay not maybe necessarily updating but if the preview of the image URL is available then we create an image tag with the source image URL which will display the image okay down below we check if the survey image URL is not available then we create a span inside there we will have this photo icon okay that indicates that there is no image basically chosen we will see how this looks like in the browser and down below we're going to have a button and this button is for the change okay that button is basically something similar we see right here okay so and inside the button basically we need input type file okay and I created the import type file gave it absolute position left top right bottom zero opposite to zero and we listen to the change event of the simple type file down below we're going to have a title with the label and with the input and the input has right here value survey title and we are also listening on change of this input and called search survey okay we Define the search server right here from the user State and the state for the survey is the entire object so we have to set the entire object and right here we take the existing survey the structure it and just give the new title okay the title in this case will be even Target value okay if we continue down below we're going to have a description and in the exact same way basically we get the value we listen on change and set the survey with the new description okay down below we're gonna have an expired date and we do something very similar to this right here down below we're going to have a check box input type checkbox which will have a checked value right here we'll listen to on change and we do something similar right here and down below it not down below but next to it basically it will have a label for active and down below this octave we're going to see a couple of like explanation text whether to make the survey publicly available or not something like this okay and at the very bottom we're going to create this t button which will have a save inside there and this button by default is input type submit okay because it is inside the form it's going to trigger the form submission and we listen to form submission right here and let's define now two methods on image choose and on submit okay now whenever we say this and have a look in the browser okay let's just reload the page okay I think photo icon is not defined so let's just move at the top and import t button as well as the photo icon so I save this let's just reload the page and here we see the Forum so we have a photo right here when I click change it will trigger the um the file choose window basically okay we have the title description expired date active and of course down below we have this button which looks really nice now let's start working on the login and registration for sending requests from the client to the server I'm going to use axios let's bring up the terminal activate the white Tab and I'm going to actually stop this and install axios mpm install dash s axios so axios if you don't know obviously you might know what's axis but it's a client to send requests to third parties so third-party apis and let's start the server npm run Dev and I'm going to now go in the source folder and I'm going to create axios client let's call it just axios.js file first I'm going to import axios from axios okay so then I'm going to create axios client const axios client equals axios dot create and right here we're going to pass an object and we're going to pass base URL okay what is the base URL so in our case base URL is the server URL on which the API is running we have our API running on HTTP TTP a local host Port 8000 and the API is on slash API okay so if we have a look in the browser again so we have our laravel application running on Port 8000 localhost and the API is right here okay which at the moment returns not found because nothing is mapped on the API URL okay but that's the base URL but whenever we are going to um whenever we decide to deploy this on production we don't want this API sorry we don't want this localhost port 8000 to be hard coded right here in the source code we want this to be different URL on production so for this I'm going to create environment file dot en file and right here I'm going to type write underscore API base URL okay and that is in that's going to be an environment variable and I'm going to set this to be HTTP localhost 48 000. so I'm going to take out the and put this right here okay so I'm going to save this and now I want to take the following URL from this dot Eno file okay how I can do this let's go in the axios and I'm going to zoom in this okay like this and pay attention so right here we are using uh single quotations okay I'm going to change this into backtick so you probably know this but there are a few uh beginners who actually don't know this this fact so you need to change these single quotations into like double into big ticks and the backtick basically is a keyboard which is above the tab so I know I'm explaining very beginner friendly things but there are a few few people who might not know okay so in right here I'm going to use the environment variable which I defined okay and that is a white API based URL so I'm going to take out this and then inside the dollar and curl braces I'm going to write import meta en and paste this okay let's zoom out now slightly okay and this will be the localhost port 8000 and then we have API now I'm going to bring up the terminal stop white server and restart it okay and we have the access client and actually I'm gonna export default axios client from here okay so that's fine later we're gonna add request and resource interceptors right here as well because when we send a request we want to pass the authorization token actually let's create the Interceptor axios client dot interceptors dot request dot use and I'm going to specify right here a callback function so this callback accepts config object right here and the config let's let's format the code the config right here has headers and inside headers we're gonna add authorization header authorization equals let's use again backtics Bearer space and right here we need the token okay and the token exists in the context provider let's zoom out so right here we have this user token okay and we want this token also to be saved in a local storage okay but we don't have that implemented at the moment because we don't have sign up and login implemented so for now I'm just gonna create a variable here token which let's say it equals one to three we're going to replace it later and then I'm going to pass token okay so we have the request Interceptor so so and down below do we have by the way in the router do we have a login and sign up yeah we do have that okay and down below I'm going to create response Interceptor axiasclient Dot interceptors dot response dot use and right here we will accept the response like this and then we're going to check so if everything is okay basically at least use accepts two callback so the first one is for successful response and if everything is okay we just return return response however if something is wrong the second function will be executed okay and right here we will get an error and then from the error we can take out the response okay if for example error.responds exists and its status exists let's do like this if error response and a response status exists and let's say that the status equals 401 which means unauthorized so we are making requests to the server and server returns 401. so we are not authorized to make these requests so then we need to redirect user to the login page okay so for these I'm going to import router and this one this was automatically imported by vs code and inside the router I'm going to call navigate and pass right here slash login okay so I want to redirect user to the login page and then down below so we are basically redirecting user to the login page we can actually return from here uh return the following error and if this status is not 401 okay then down below we can just throw error 46 02:00:44,699 --> 02:01:44,000 okay so we have these axios almost ready the only thing is to replace this token let me actually leave to do right here okay and now we can go on the bacon side and create the controller and implement the sign up and login so I'm going to bring up the terminal open the second tab inside which I have these Artisan server running let's clear up everything and I'm going to create request classes in the alt controller PHP artisan make request let's call this sign up request let's hit the enter I want to create login request hit enter and I want to create auth controller let's hit the enter okay I have created those files let me actually close everything and let's open alt controller okay um 47 02:01:44,580 --> 02:03:38,300 my bed my bed I made a stupid mistake so the alt controller okay I generated out controller using a make request so let's clear up everything let's delete the alt controller and I want to create I want to create a controller make controller out controller all right now if you go into controllers we have alt controller right here let's start the server and PHP Artisan serve okay and let's create right here three methods um it's going to be sign up we're going to accept right here sign up request and it's going to be requests and that doesn't return anything well it's going to return but I'm going to remove this and let's import this sign up request okay right here and let's leave this empty at the moment I'm going to create a login we accept login request let's hit the enter and that was also automatically imported and we have requests right here and let's remove this and I'm going to create log out okay and we accept just requests right here request class okay and that is illuminate HTTP request and the variable is called request okay so we have all three methods now let's open api.php scroll down below and let's define those roles wrote uh one column get for slash sign up we are going to use alt controllers 48 02:03:38,699 --> 02:10:29,599 sign up okay let's duplicate this and change this into login all right we have this API rating and if we go in the out controller we have this basic methods already as well now let's start the implementation with the sign up method and first of all I'm going to get all the requests validated data okay so then I'm going to try to create user so right here I annotate the user variable to be an instance of app models user that is very useful thing for the IDE slash Editor to autocomplete methods and properties on the user so I call user create I pass the name email and password however the password needs to be encrypted okay so I just created user basically after it was validated we haven't yet written the rules for the sign up request but we will do this later okay so imagine that the rules are there so we got the validated data and created the user now down below I'm going to call create token on the just created user variable I give it a name Main and just get this plain text token okay so when whenever you create token you can get the plain text token only at that time when you actually create the token okay later you cannot get this plain text token and we have this token and now I'm going to return a successful response returning the user information as well as the token okay and just like this we have the sign up method ready now let's scroll down below and create login method so we're going to get the credentials from the login request okay and that's going to be validated data then we're going to get the Remember Me Property from this credentials as well if that doesn't exist we get false then I'm going to unset the credentials remember from this so that I will only have all email and password inside the credentials and then I try to log in with the credentials and the Remember Me Property okay however if the out attempt returns a false we're going to return with the error message provided credentials are not correct and the status code 422 okay and down below we get the authorized user basically if the user was successfully authorized the if statement will not be satisfied and then code comes right here we get the user and on the user we again create the token we get the plain text token and finally we return the same type of response we returned from the sign up method okay so far so good now let's scroll down below and right here I'm gonna get the authorized user so on logout I get the authorized user and I also annotate right here the user is an instance of the user model and we need to import this user by the way and we will do this right now uh and down below we are going to get the current access token of this authorized user and call delete on this okay and finally we need to return some kind of response and the response is just success true okay so we have the logo already and now let's import few classes and let's start from the top so we have user right here let's import this and we're going to use app models user and it was imported right here next is to import Alf and the alph needs to be facades out and the first one so let's have a look so here it is that was imported and do we have anything else no I think everything is good so far so I think we have the backend ready now we can open signup.jsx file and start the actual user registration now let's start working on the form but first let me open in the browser and this page my admin let's go in the sign up and we redirected to the log to the dashboard because inside context provider we have some tokens so let's just remove this token and now we are on the login page and I'm going to go into sign up okay this is this is our sign up page now let's modify in we're going to add right here a full name as well as the password confirmation and we're going to change the links here as well so let's go in the sign up and start step by step let me zoom out slightly so we have email right here this is the field for email let me actually copy and paste this here and we're going to change that uh the English format code um so right here I'm going to call this whole name let's copy these and change in both places full Dash name the name that's going to be just name the type needs to be text autocomplete let's just remove autocomplete we have required in the class name and the placeholder will be full name let's change this into lowercase U so let's save this and have a look so we have full name okay now pay attention if we zoom in so we have a rounded corners on the email address okay we don't want that we want only roundage to be on the full name so let's tell in CSS classes so this is the full name let's scroll down below we have email and somewhere right here we have rounded TMD which means top rounded top MD so we'll just remove it and we don't have around the top on email address anymore perfect let's scroll down below and now copy the field for password and duplicate this and now um this is the second one let's just call this password confirmation let's change this password into something like password Dash confirmation by the way so the html4 and ID can be password Dash confirmation however the name should be password underscore confirmation as well as the type type needs to be just password for the autocomplete I'm going to just remove it we have required and the placeholder needs to be password confirmation awesome now let's have a look in the browser and on the password field we have rounded bottom so let's just change these rounded bmd let's just remove it 49 02:10:32,040 --> 02:11:01,400 save and here we go so we have full name we have email address password and password confirmation okay let's remove you a few things so first of all I'm going to remove this remember me we don't need that and about the forward password we don't need this either so I think we can remove this complete div let's just save this and this is our button let's change the text into sign up 50 02:11:02,460 --> 02:11:42,080 and I think I think we have the input send button ready let's change the text right here I'm going to set this into login with your account something like this and we're gonna link this to an actual login page so I'm going to use Link tag for this and let's change this into two and the path needs to be just logging okay so I save this and the link is not defined I think a link is not imported 51 02:11:42,780 --> 02:13:03,320 the uh no this is something else link oh for some reason Auto importing uh does not work it doesn't find this link from the react router down so we have to manually write this import import uppercase L link from react rotor done all right so we save this and now let's have a look in the browser or log in with an account just click right here and the login page is open okay let's let's go back so sign up for free we have full name email address password password confirmation sign up button and link again perfect now let's go back and work on this registration and actually send requests to the server side to register the user so for this I'm going to Define States few States right here okay so we need full name and set full name let's use state and by default it's it needs to be an empty string okay so let's duplicate these few times and here we're going to have email 52 02:13:03,719 --> 02:13:08,480 we're going to have a password 53 02:13:10,199 --> 02:13:14,820 and password confirmation 54 02:13:15,900 --> 02:16:53,901 set password oops confirmation let's change these into lowercase p and we have full name set full name email password and password confirmation and down below I'm going to create also a variable for errors so if there are some kind of Errors like email is used or something else we're going to display the following error so let's let's create set error right here as well and we might need we will need definitely to display these errors as an HTML so basically I'm going to give the default value right here to be an object and inside there we're going to have HTML corresponds to an empty string okay and you will understand why I did this okay so we have everything not everything but we have this state ready and now we're going to implement the actual sign up uh we have formed somewhere and we need to listen on submit of the form we will get an event and we're going to call on submit and pass the following event we can actually pass on submit right here why I did this on submit okay now let's create this on submit method const on submit is a function we get event right here first of all I'm going to call prevent prevent default okay so then and then I'm going to make an axios request okay so also let's just call set error so if there are already some kind of Errors available inside the form I'm going to just reset them so underscore unscore HTML corresponds to an empty string and then I'm going to call axios okay axios client the outer composition doesn't work okay access client dot post we're going to make requests to sign up page and we're going to pass data okay inside data we will need name and the name needs to be full name we're going to pass email we're going to pass password and we're going to pass password underscore confirmation con here mation to be password confirmation like this okay and whenever we get the response then we will get the whole response right here but I'm going to destructure the response and take out data okay I'm just interested data because the whole response contains the headers as well inside which I don't need at the moment so I give this data and let's print console.log the whole data okay and we're going to also handle catch case inside catch we're going to get the error okay and I want to destructure this error and take out response from here okay and then on this response let me actually print the whole response first of all what is the actual response because that's going to contain errors as well okay I'm going to format the code and now I think we can test how our code works so let's go in the browser and I'm going to open developer tools let's zoom out slightly calling the network - and let's fill up the information so I'm - going to just type 55 02:16:54,840 --> 02:17:12,679 some random data and hit sign up okay the first error access client is not defined obviously we haven't import the access client so let's just write import axios client from 56 02:17:13,080 --> 02:17:19,939 axios let's save this and click sign up 57 02:17:20,760 --> 02:17:28,040 okay let's just reload the page okay now let's fill up the form again 58 02:17:29,899 --> 02:17:55,880 and hit sign up okay we we get undefined and the undefined comes from the uh inside cage and let's see did we made we make requests I don't know let's hit sign up okay nothing really happens and we always get undefined it looks like we are not sending any kind of a request 59 02:17:56,280 --> 02:18:08,960 so we have post access client okay what is this axis axios Dot Js 60 02:18:09,599 --> 02:18:30,679 it is this one and I think we are exporting the access client in the access client should have a pulse request okay now let's check this once again on submit we're making request and it comes inside catch 61 02:18:33,179 --> 02:19:22,519 all right let's test this once again I'm going to click sign up we get the undefined now we need to debug and find out what is the actual problem why we get inside catch okay what is the information so I'm going to put the breakpoint right here and just hit the sign up now let's understand what is the full name full name is empty email is empty password is empty password confirm everything basically is empty okay that's that's I think logical because we haven't implemented like two-way data binding on those variables which is fine but why the request is not made let's go in the xhr okay either we don't see or the request is not actually made we don't see the request made right here 62 02:19:23,519 --> 02:19:36,260 maybe something is let's just remove the developer tools reload the page reopen it click sign up okay we have to fill up 63 02:19:40,859 --> 02:20:32,600 hit sign up let's continue and no no actual request is definitely made okay so we need to debug the problem and find out what's happening so right here we print the response but the response is undefined but let's print the actual the entire error so definitely we have something wrong okay in Winter find out what is our problem let's print error save this and click sign up okay let's proceed go in the console and here we have this error cannot read property to find the file reading cancel token what is this cancel token okay okay let's go in the axios 64 02:20:33,060 --> 02:23:24,540 okay I think I think I missed that we need to return config from here okay we just save this and now have a look let's hit sign up and proceed okay now we have progress so the request was made go in the network we are making post requests but the method is not allowed so obviously I made a small mistake in the API PHP because the request method should be post okay I save this and hit sign up now I proceed once again now let's have a look we have another error this section is unauthorized okay what action is unauthorized so we're making requests to the API sign up we get forbidden why do we get forbidden because I think on the backend side we have not implemented the sign up request in the login request okay so if we go in the sign up request right here inside the authorized method this returns false and that's why we get the following error okay so and down below we don't even have rules written nor in sign up request not only in the login request okay this is something right now we need to take here and let's start with the sign up so right here we're going to Define that the name needs to be required and it needs to be string we we're going to need an email which must be required and it must be valid email address string and unique inside users table inside email call okay and down below we need password which must be required and it must be confirmed which means that there must be another field password confirmation okay and then we're going to set the rules for the password needs to be minimum eight characters we need mixed case numbers and symbols all right and just like this we have the rules ready let's just import this password facade and change this authorize into true okay now let's go in the login request and we have to implement something some something similar right here so I'm going to Define let me actually copy email here and so we need to make few things like this must be required email string exists okay I think everything is good and then oops right here inside password we're going to specify that the password needs to be required okay and 65 02:23:24,899 --> 02:23:33,740 and we're gonna have also remember which must be Boolean 66 02:23:36,060 --> 02:24:16,580 foreign this and change this authorize into true and now let's go in the front and side and make request so I'm going to click sign up now and proceed let's remove the breakpoint by the way let's go in the network click on the third request and we get call to undefined method password okay okay inside the login request now inside the sign up request I imported password facade but it should be rules password 67 02:24:18,780 --> 02:27:54,680 let's click sign up again okay and this is something I expected we get the following errors that the email name password all of them are required why because we don't pass that information okay and why we don't pass because we have not implemented two-way data binding but that is good that we get the errors we need to implement error handling as well so now if I go in the vs code open the sign up jsx and right here I get the response okay and inside here I want to basically print the following errors somewhere maybe about the form right here okay so how I can do this uh we get right here error and we need to take out response as we were doing previously or we can do it in a more like a safer way so we get the error and we check if air dot response exists okay to avoid the case what we had previously so if there is some kind of other error rather than server error then the error.response will not be defined okay and in this case we can just print console console maybe sorry console dot error and just print there okay however if the error response exists we're going to get the actual errors from the backend okay and we will get them from error.response dot data okay the response is the entire axis response we want the data and data is actual result and the actual result in this case is the following Json okay and the following Json this Json has errors inside okay so I want to get dot errors from here okay and the arrows is an object it has email name and password right here so basically I want to get a very first errors from area so I'm going to call object dot values from from the following object from the following object okay and that's going to be an array of Errors so it's going to be an array of arrays okay imagine that I get this and this and this and then I have an array of these values okay it's an array of of arrays and finally I'm going to call reduce on this to just convert this array of arrays into a single dimensional array okay and right here I get the accumulator I get the next and then I basically let me actually pass an empty array as an initial value and I'm going to return the to the structure the next and the structure the accumulator okay so and finally I want to assign this to some some variable and it's going to be like um shall we call it errors I think we can call this errors I think I have a typo right here 68 02:27:55,439 --> 02:28:12,120 okay so we just concatenate two arrays right here and finally we have errors and let's just call this final errors okay so we can print these console.log 69 02:28:12,859 --> 02:29:35,960 console.log by now errors and we need to set this into State okay let me call set error and I'm going to pass right here an object we're going to have underscore underscore HTML and we're going to pass the final errors but I am going to I'm going to in like combine them with the BR take so finally I'm going to call final errors dot join and I'm going to pass BR tag right here okay and now down below right here I'm going to display these error State basically so right here in this place I'm going to check if the error underscore underscore HTML exists then I'm going to render the following div which has a background red and rounded and padding and text white and I'm going to Dangerously set in your HTML okay and that's going to be the error which we just set using by calling this set error okay if I save this and open the browser and hit sign up and we need to fill up the form 70 02:29:38,160 --> 02:30:28,700 let's hit the enter and here we got the errors okay the password field is required email is required so basically okay let me change one thing so right here we are concatenating next in accumulator but let me just change the ordering so first I'm going to take the accumulator and then next click sign up okay now we get this name email and then password okay no we need to actually Implement two-way data binding into pass that information to the server okay so let's go in the input fields and we're going to pass a value to be full name okay and we listen on change 71 02:30:29,160 --> 02:31:31,200 and we get the event and then we call set full name and we pass event Target dot value and let me actually print right here the name or full name I think it's called full name so now if I just start typing I see that the full name is updated okay and if I just make a request we don't see any errors about the full name because if we have a look in the payload let's expand this the last request payload has a name right there okay and in the exact same way we're gonna do this two-way data binding on the email password and password confirmation however we're gonna change this into password confirmation set password confirmation 72 02:31:32,460 --> 02:38:03,800 here we will need password set password and here we need email and set email okay now if I make some changes set the password hit the sign up okay I get all the errors about the password okay there's no error about the name or email all the errors are related to password the password must be at least eight eight characters and blah blah - blah so let's just provide a valid - password and clear up the network and hit the sign up okay look at this we got the successful response 200 status code and whenever we get 200 status code we need to set the users token okay if we scroll up right here by the way we also have this inside inside console we get the token in the user Okay so right here okay let me delete these and I'm going to now use uh use two methods from the context provider one is the set user token and second is the Set current user okay and the current user information basically we can already clear this up and just leave an empty object okay and we have set user token and Set current user inside the value so if I just write const and take out uh let me actually write first date use context use how it's called use State context use State context okay and then right here we're going to get Set current user and set user token okay we get both methods and right here I'm going to call Set current user equals data dot user and set user token equals data.token okay now pay attention what will happen whenever we get the successful response and we set the user and we set the token okay it's going to update the state and now user token will become available and if we open Now default layout right here we have a logic no not the default layout but the guest layout okay we are already in the guest layout uh the actual sign up form is inside the guest layout and in the guest layout we have logic if the user token exists we are redirecting user to the slash okay and whenever we call the method set user token from this sign up form then we will be immediately redirected to the dashboard okay if you don't believe me and if I don't have any bug I'm going to test this and prove that I am correct so I just specify right here okay let's just remove the name here okay I actually already registered the user with my email so I will quickly open the users table and delete this one I don't need that no let's just provide my email and let's hit sign up okay look at this as soon as we got the successful response the token was set user information was set and we were redirected to the dashboard okay isn't it this awesome and if we have a look in the Mobile screen we see my name in my email as well right here okay so the only thing we need to do here is to set the inside the context provider we need to set the uh inside the local local storage window set the token so right here I am exporting so-called exporting not now textual exporting but putting inside the value and becoming the available this set user token okay what I'm going to do is to define a Define a method with the same name set user token equals to A narrow function however I'm going to change the this end call this underscore set user talk okay and right here I will get the token and I set I I check if token exists then inside a local storage I'm going to call it set item and inside the token I'm going to save the following token okay in else case I am going to call on local storage remove item token okay and finally I'm going to call underscore set user token and pass the following token okay now if I why I did this okay because I need to have this local storage um to contain my token once I am authorized and I just reload the page I want the token to be inside the local storage and I still want to be authorized now even though I registered and I was on the dashboard I'm logged out okay and now I need to log in we don't have yet login implemented and we're going to do that for sure but let's again once again test the sign up but I'm going to make small correction right here so the default value of the user State for the user token will become local storage get item okay and if that doesn't exist let's assume it's an empty string okay I save this let's go in the sign up and provide the information let's change the email address 73 02:38:05,280 --> 02:40:25,280 and hit the sign up okay we are on the dashboard if I now open the terminal and type local storage we see token right here and if I just reload the page I am still on the dashboard why because we got the token and save it in the user token variable State and whenever the user token is available we are on the dashboard okay I think that's really good and now I think we can already start working on the uh on the login so for the we don't have log out so I'm gonna just manually clear up local storage and just reload the page and now on I'm on a login page and now let's implement the login form now let's open login jsx file and we're going to do basically something similar so I'm going to copy and paste few things from the sign up js6 so I will need the following errors so I'm going to put this inside the login right here okay I will need the email and password so I'm going to take out this and this right here I will obviously need on submit so I'm going to take out this and maybe take out everything of this on submit and paste it right here however we are going to make requests on slash login we are not going to pass name we are not going to pass password confirmation whenever we get the data we're going to call the same methods and on errors we do also something similar okay we can even remove this final errors console log and in the down below we will need two-way data binding like this so let me actually take out the email one and paste right here so we have for the email and for the password let's change this into password here and set password 74 02:40:26,100 --> 02:40:55,640 and a few more things so instead of start your 14 day free trial let's write uh sign up for free okay down below we have the forward password link which I'm not going to implement so I'm going to just remove it save this and your state is not defined obviously so let's just 75 02:40:55,979 --> 02:41:26,359 let's just delete the last letter and import your state from react I say this error is not defined yeah I think we need to Define error and set error as well and by default this needs to be an object with underscore underscore HTML to corresponds to an empty string okay so we have sign into your account or sign up for free 76 02:41:26,939 --> 02:41:42,560 I think sign up for free needs to be a link and it needs to have two right here to go to sign up and I want to import the link 77 02:41:43,979 --> 02:42:07,880 from react rotor Dom I save this format the code and click on the sign up for free it opens sign up page click right here it goes back to the login okay now let's have a look in the network and let's just make requests hit sign in 78 02:42:08,220 --> 02:43:17,660 okay we are not doing everything correctly I think we don't attach on submit on the form this is good now let's click sign in again and we have an error access client okay we need to import access client from axios so I save this and click sign in once again email has already been taken okay what is the problem so we are making requests on slash a login why do we get the following error I think I think because inside the login request we shouldn't have this unique rule I don't know why I have this but we shouldn't have in my opinion okay so let's just save this and click sign in okay let's have a look okay we got the response 79 02:43:18,240 --> 02:46:17,700 Set current user is not take Okay um if we go in the login and basically we can copy those this line and put this in the login.s6 okay and we need to import the use State context like this and if I just clear up everything go in the network clear this up and hit sign in now we are on the dashboard okay we have been successfully logged in now and if I just reload the page I'm still on the dashboard because the information the token was saved in the local storage okay so far I think is so good now let's Implement logout as well let's open default controller sorry default layout and we have somewhere logout method okay so from here we're going to make requests to now I think access client was imported yeah it was imported okay so we're going to make post request on slash logout and we get the response and whenever we get the response we will just call Set current user well basically we need to use uh State context we have right here current user and user token let's just let's just import and not the import but take out the Set current user and set user token as well and right here I'm going to call Set current user and pass an empty object and I'm going to call set user token in pass now right there okay so whenever we click the logout it's going to make request and unsuccessful response we just delete the token as well as the user information now if I open the browser open the network and hit the sign out the request was made I think it is in pending okay let's have a look I think we haven't configured the log out yeah we haven't configured the log out okay the logout should only be made when the user is authorized so inside the root middleware of sanctum basically which makes sure that the user is authorized okay let's just remove this get user we don't need that okay and I'm going to call group and then inside there we're gonna write roads post slash logout we're gonna use out controller 80 02:46:18,240 --> 02:46:33,560 oops log out okay now let's hit let's clear up and hit the logout and we get 81 02:46:34,080 --> 02:46:53,580 we get some kind of ER okay it was blocked by course okay what is the reason Okay the reason for this might be that we are not actually sending the correct token okay so if I just open axios 82 02:46:54,540 --> 02:47:32,060 and right here we're just sending the token okay this one one two three so instead of these we might need to write a local storage get item token okay we get the token and pass this and now let's have a look so if I just reload so we have inside the local storage we have this token now I click right here and click sign out okay in the response is again complaining about course okay is the backend server running let's check it out 83 02:47:33,420 --> 02:49:18,560 okay we have some kind of syntax error okay that is the reason we go in the API semicolon is missing right here let's just save this okay we don't have an error now let's click sign out and we are on the login page okay and if I check now local storage it is empty okay so my token was deleted my local storage token was also deleted also from the database the token was deleted basically I was logged out completely and now I click a login sign in and I am on the dashboard page okay so we have logout as well now let's start working on the saving surveys and first let's implement the backend side I'm going to close every Tab and just generate new controller let's Stop The Artisan server PHP artisan make controller and I'm going to call this survey controller okay so we're going to also generate request files as well as resource file so let's run PHP artisan make request create survey or survey store request I think that's going to be more relevant survey store a request hit the enter and the second one is to be survey update request let's hit the enter and I'm going to generate a resource 84 02:49:19,319 --> 02:49:23,160 survey resource 85 02:49:23,760 --> 02:51:03,319 let's hit the enter okay so I think I have created all the necessary files I want and now let's open survey controller and let's start implementing from here um by the way whenever we generate new controller we can specify that I want this controller for the API and this will create additional methods like the necessary methods for the API so let me actually delete this survey controller and let's execute make controller but I'm going to specify Dish Dash API flag okay now let's open this survey controller and let's have a look so we have now index method here we have store we have show update and Destroy okay those are the methods we want and in the store we want to use uh survey store request for the update we want to use survey update request okay and let's start implementation from the store so right here we're going to get the current user information that's going to be user request user okay and then I'm going to return all the surveys where the user ID of the survey equals to the given user ID okay the authorized user ID and I want to order them by 86 02:51:05,100 --> 02:51:21,740 so we sort them by uh created it and we can specify that we wanted to be sorted by descending and then I'm going to call get okay I want to get all the surveys let's import the survey model by the way 87 02:51:22,100 --> 02:51:34,760 survey don't we have the survey model the import does not seem to be working okay let's check if we have 88 02:51:36,359 --> 02:56:09,380 no we don't have actually models did we create migrations no I think we haven't even created migrations which is well which is something we need to do right now okay so we don't have a model we don't have migration okay let's have a look at the plane We are following so we have implemented the following things from the very beginning and we need to now generate database schema and create models related to surveys and questions and answers all right let's have a look at the schema which I prepared so we have obviously user table and the user table has surveys okay one user has multiple surveys and each survey belongs to the user for the survey we have name we have slug we have status description created data updated and expire date then the survey has questions survey question table basically and by the way when we generate tables I think the table names will be in plural and this is how it should be okay and we're going to have for each question type and the question in description and data and created it and updated it in the survey ID to which survey the question basically belongs to and we're going to have also survey answers table with the survey ID and the date and the start date and end date however this started and end date is something which which is something which might be useful in the future basically if we try to um try to show some kind of analytics when the user started the survey and when user finished that survey okay and we're gonna also have survey question answer where we save the question ID and the answer ID and what is the actual answer okay now we're going to follow this and generate now models immigrations and basically start working on the backend side and implement the saving of the surveys and questions and so on okay so let's start now step by step I'm going to open my vs code bring up the terminal and now we're going to generate we're in generate models okay so PHP artisan make model the first model I want to generate is the survey model okay so let's just specify survey right here and I want the survey to be generated with few other resources few other classes okay so I want the migration file to be generated I want the resource to be generated Dash air okay let's actually have a look in the documentation laravel make model so I'm sure the the make model basically supports a lot of a lot of additional Flags make model okay so if we want generic migration we're going to use Dash M so if we want controller we're going to use Dash C so in this case we want controller as well - so let's put right here C we will need - Resource as well okay we can use the uppercase R for lowercase R for resource and uppercase R for requests okay this is basically what we need Okay C lowercase R uppercase R immigration of course C lowercase R uppercase R okay and let's hit the enter okay it generated the model it created the migration file now it's working and it's going to create controller as well as the requests okay let's hit the enter it General doesn't need that much time let's go under database migrations and immigrations generated and here we have everything okay so let's let's have a look so we have the migration file we have the store survey request update survey request we have the survey controller and where is the resource by the way 89 02:56:11,540 --> 02:58:54,620 I don't see a resource so why I don't see that we have controller resource and requests did I miss anything no I haven't missed anything okay so we can make the resource manually but it should be generated okay let's now open survey controller and let's have a look if we have all the methods for the API so we have index and create and store and show and edit and update and Destroy I think few of them is something we don't need so for example we don't need to create because that controller basically is not intended for the API that controller is for the websites okay and this create is just for rendering the form so this is something we can remove as well as we can remove I think edit okay where we just have to render the edit survey form so we will remove those and let's generate resource PHP artisan make resource survey list let's call it this survey resource let's hit the enter okay it's every survey resource was created now let's follow and generate other models and immigrations so here is here is the schema and let's create now survey question PHP artisan make model survey question and we don't need separate controllers or requests for the survey question that's going to be part of the survey controller okay so I'm going to hit the enter and let's generate survey answer hit the enter and we're going to generate survey question answer as well survey question answer hit the enter all right so we have all the models let's close this we have all the models um maybe I I just forgot okay I feel stupid sometimes so uh I forgot to generate those with the migrations so I think I have to delete them we have question and answer and sorry answer so I just delete all of them and generate with migration 90 02:58:54,899 --> 02:59:03,620 creating migration takes some time and now let's generate survey answer 91 02:59:04,260 --> 02:59:12,620 and let's generate survey question answer with migration 92 02:59:14,160 --> 02:59:30,140 all right and let's now open migrations folder and start from survey okay so let's clean up everything and run PHP artisan serve no I think we don't need that 93 02:59:30,540 --> 03:03:32,479 let's close this and let's start writing migration on the service table we need the foreign ID for the user that's going to be user ID we will need the string image we will need Title we will need slug we're going to need status which is going to be tiny integer and we need description which must be nullable on the survey and finally we need expire date okay now let's open create survey questions migration file that's going to be next to below the service migration file and then we will need type right here we need question we're going to need the description which can be nullable we will need data which is going to be long text and it's going to be also knowledgeable okay and we will need for link ID on the survey model with the survey ID okay and just like this we have the survey questions migration ready let's open create 8 survey answers right here we will need to have folding ID for the survey so we don't need timestamps okay according to the schema we prepared we just need the following ID for the survey with the survey ID we will need timestamp with a start date which is going to be nullable and we will need end date which is going to be also nullable okay in the last table is the create survey answers table okay and right here we will need again foreign ID for the survey questions with this survey question ID we will need folding ID for the survey answer with the survey answer ID and we will need an actual answer okay this is according to the schema we just reviewed okay like this so now we have the immigrations ready now let's bring up the terminal and run PHP Artisan migrate hit the enter all the four table migrations have been applied and now let's open phpmyadmin reload it and we should see few more tables right here sorry answers and questions and surveys itself okay so far so good now we can start the server HP Artisan serve now let's close this let's close all the migration files and now I think we can start working on the let's open survey controller we can start working on the surveys okay so when open survey controller let's open a survey resource we will need just store survey request and update survey request okay we're going to start from those files first let's start with the store survey request and we're going to define a few rules so first of all I'm going to define Title which is going to be the required string and maximum length we will need rule for image for user ID we need status we need description we need expired date which must be knowledgeable in date and its value needs to be after today okay and we will need questions here as well which must be an array okay so I save this and I'm going to change this authorize into true and I want to create right here an additional method which is going to be prepared it's going to be protected protected function we appear for validation okay and right here I'm going to get the current user ID and put this inside user ID so basically I'm going to call this merge and I specify right here user ID corresponds to this user ID 94 03:03:33,240 --> 03:16:30,140 okay semicolon right here okay so just like this we authorized we prepared the data for the validation and put the user ID and then the rules will be executed okay now let's open update survey request and in the same way we need right here title we need image user ID we need the status we need description we need the expired date to be nullable in date we need questions and um yeah and by the way the expired date needs to be after today here and then we need to allow authorize but not directly like this okay so we should not allow modification of the survey to the user if the user is not the owner of the survey so how we are going to detect if the user is uh owner of the survey or not okay so we're going to get the current survey which is in the URL which we are trying to update and we're going to check if the service user ID is the authorized user's ID okay so let's assume that we have that survey uh survey okay let's assume that we're going to implement this okay let's assume that we get this survey and then we're going to write an if statement if and this which is the request if this user ID does not equal to the survey user underscore ID then we return false okay otherwise we return true now let's take care of getting this survey so we're going to get this survey from the root and if we open API and let's by the way Define the survey resource so wrote API resource and I'm going to specify survey right here and the controller needs to be survey controller okay and whenever we do like these and on the update request the survey will be available inside the survey key of the root so basically if I just execute these approach survey this will give me the survey model okay and then on the model I execute the following logic okay and just like this I have the star survey request and update survey requests ready let's start with the survey controllers index so first of all we're going to get right here request and then we're going to get the current user from the request okay so then we are going to return the result of the query so I'm going to execute survey model where so right here I'm going to use user ID is the currently authorized user ID okay and I call then order buy to order those surveys by creating it in descending order then I'm going to call paginate let's say imagine it with 10 items and this will finally return the pagination result okay and we need to pass that result to the survey collection so basically I'm going to call survey resource sorry resource collection right here we pass the following result and just like this we return the result of this survey resource the survey resource I think it needs to be imported it is actually already imported okay and just like this we have this index method ready why does vs code complain return value of index is expected to be type of response or something else I think that's fine now let's scroll down below and start implementing the store method so for this first of all we're going to get the validated data okay then we're going to check if the data contains image inside there we're going to save that image that image in a local file system okay so I basically take that data image and pass it to a new method save image the save image does not exist yet but we're going to create that soon and I decided to put this in new method because there will be some kind of logic for saving an image which is not relevant to be inside the store method it is it's kind of relevant but I decided to have a dedicated function for that okay so then we have the relative path um and when whatever is returned from this save image is going to be saved in a relative path so I take that relative path and save it back inside the data image okay and then so after completing this code we have the image saved and then finally we call survey create with plastic data and down below we start iterating our questions and I want to save every question basically okay so I get this survey ID and assign it into the question survey ID and then I call this create question and pass the question again this create question doesn't exist yet but we're going to create that soon okay and finally we're going to return the just created survey and pass it to the survey resource and just like this we have the store method ready all right now let's scroll down below and create this save image method okay so there's going to be private method save image which will accept an image and then we start writing some Logics so basically when we are trying to upload an image there are many ways to upload it and the most common one is to upload as a form data and then you accept normally as an uploaded file if we are speaking about the like vanilla PHP or a language is going to be a dollar sign underscore super Global files basically okay the second way which we are doing at the moment is uploading and sending to the server as a base64 string okay why I do this because my request type which is which I will send from the front end is a Json okay I and I wanted it to be Json yeah I didn't want to to change into form data so that's why on the client side we have to read the file convert this into base 64 string and send it like this okay this is how we're going to prepare our API so right here we basically going to do a basic checks so if the given image basically matches the following pattern okay if it starts with the data image and then it contains slash right there and then it contains some alphanumeric symbols more than one and then if it has semicolon and base64 comma then basically if that happens then this is a valid base64 string okay and inside there we're going to take out the base64 encoded text without the mime type so basically I am taking everything uh after the last Corner which is going to be this okay everything after this portion to the right side that's going to be base64 encoded text okay so and that's going to be the saved inside the image then um I also take the type whether it's a JPG or PNG or GIF okay so I take the type then I check if the type is not inside one of the supported file extensions so in this case we're going to throw an exception in the valid image invalid image type okay however if it is we continue and we just replace inside the image in the SpaceX divorce ring if there is any kind of space we replace it with a plus symbol okay then we decode that base64 string and save it back inside an image and then I check if the decoding didn't happen for some reason and if the image is false we again throw in exception Basics have already code failed uh in the else case and that else case is right here if the preg match didn't work okay if the image basically doesn't satisfy the following condition then again we throw an exception didn't match the data Theory with image data and then we create we prepare the directory to save our image into so we have a d right here we're going to create a random file name using Str Helper and we're going to create an absolute path and we're going to create also relative path and then we check if the absolute path does not exist then we make the absolute path directory and then we put the given image inside the relative path okay and finally we are going to return the relative path which will be then saved inside the database okay so I think we have this method ready let's just import this Str helper eliminate support Str hit enter and let's just import this file as well but we have a lot of options for the files which one do we need so I think we need a file either facade or support think this is what we need Okay so we have this method ready and now we can create the second method which was to create questions now let's define another private method to create a question okay then we need to check if the data given inside the data exists if it's an array okay if it is an array then we decode the data and save it back inside the data data so the data basically is data of the question and inner data will be an option so if the question type is for example select or check box then it's going to have options and that inner data will hold those options and it's going to be Json string so we need to decode um sorry we need to encode that and save it like this in the database okay so technically this is going to be it should be a Json string but it's going to be an object coming from the front end so we have to encode this and save this as a string in the database okay we're gonna see the final result of course and you will understand definitely so then down below we're gonna make the validator okay with the data and let's define the rules for the validator we're going to specify the question must be required in string the type needs to be required and here we introduce enums okay so we're going to create question type in um with four or five question types we decided to support in our uh sorry application and down below we're going to have a description we're going to have also data needs to be presented and then we have the survey ID which must exist in the survey model ID column and finally we're going to return the result of survey question Creation with the validated data okay and just like this we prepare the following method create question however we have to import the validator that's going to be 95 03:16:30,540 --> 03:17:59,479 illuminate a validation validator or illuminate support facades validator it needs to be facade facades and let's include enum as well and that must be num um Rule and right here we need to import the survey question as well okay so we have this ready and let me collapse this and scroll up and let's implement the other methods like show for example show is pretty straightforward we're going to accept right here request then we get the currently authorized user information from the request and we check we need to make a validation check so if this survey which we are trying to update now which we're trying to return not update but which we're trying to return to the front end does not belong to the authorized user we basically don't allow this so security is the number one thing you should always consider when building an application just getting the survey and returning might not be good idea okay we might need to check if the user has permission to read that specific survey so in this case I'm going to check if the user ID does not equal oops delete survey 96 03:18:00,120 --> 03:25:12,920 sorry survey user underscore ID then we're going to return with a board 403 and the message needs to be unauthorized action okay NW we will simply return new survey resource and pass survey right here okay and just like this we have the show method ready and now let's focus on the update that's going to be more challenging now first of all let's get the validated data then we're going to start again checking if the data image exists and if that exists we're going to again call the save image to get the relative to save the image and get the relative path we update the data image and then we need to check if the old image exists we need to delete that okay whenever we are updating the survey so we check if the survey image exists then we get its absolute path and then we call file delete on this absolute path okay and down below now we need to update the survey with the data okay but we need to update the questions as well and this is the where the things getting a little bit challenging so we're going to get IDs as a plain array of existing questions okay the questions which are in the database we get those questions we call plug on that and two array and finally this will give me a single dimensional array of IDs of these of this survey from the database okay then I get the IDS as a plain array of new questions which is coming from the request okay now all this is existing IDs in the database this is new IDs and I'm going to now compare these two arrays and understand which questions should be deleted which one should be created and which one should be updated okay so I start now this this comparison so I call array div with existing IDs and new IDs and if there are some ideas which are in existing but not in new IDs that's going to be finally in this 2D delete variable and then this 2D to delete is something which needs to be deleted so I prepare this to delete variable then I prepare to add IDs variable as well in this case we subtract we not subtract but we call array div on the new IDs first in the existing ID so in this case the IDS which are in new ideas but not in existing IDs will be saved in the to add okay down below we call destroy on to delete IDs and this is going to destroy and delete all the questions which is right there and there's going to be an array okay then I start iterating over data questions and I want to create Now new questions okay and right here I check if the question ID from the all the questions we received basically okay we received like a couple of questions and some of them were new some of them we're about to be updated okay and we check if the question is inside to add array then we need to add new question and right here I prepare the question data give it survey ID and I call create question already existing method okay and then down below I have to update an existing existing questions so I take that data questions and convert this into a collection and then index it by ID so basically finally the questions map will be an associative array where key will be the question ID okay then I start iterating over the database questions of this survey and I check if the database question ID exists inside the question map then I am going to call update question method as right here the database model and the second argument will be the new question new question object coming from the front end from the browser okay this method does not exist but we're going to create that and finally we return this new survey resource with the given survey model okay so the only thing right here is to create that update question method now let's scroll down below and create that method so that method will accept the survey question database model and the date okay and we're going to check if the data contains inside their data which indicates that now if this might be a select type of question or checkbox or radio okay so then we take the data and encode it and assign it back to data data and down below we call the validator make to make a validation on the given data we give it an ID which must exist inside the survey questions model inside the ID field okay then we also give a question must be required in string the type needs to be required and one of the given question type and values and the description and the data must be presented and finally we are calling question update with the or validator validated data and just like this we have this method ready okay now let's Implement destroy method okay so right here we're gonna get the let's assume that we already have a request right here so we're going to get the user from the request then we're going to check just like we're doing in the update or in the show so we check if the user ID doesn't equal to the survey user ID then we return with 403 with unauthorized action okay then down below we're going to call survey delete we're going to also check if the survey image exists so we need to delete this image from the file system so I'm going to call absolute path public path to get the absolute path of this image then I'm going to call delete on this absolute path and down below I'm going to return an empty response with status quo 204 meaning that everything was successfully completed okay now let's define right here request which needs to be every request variable all right I think we have that ready let me check few things so here we have the update we are updating the survey however I think we don't check 97 03:25:13,800 --> 03:26:47,899 I think we don't check uh yeah we don't check it right here if the current user is authorized to update the survey because we check this inside update survey request okay right here so pay attention whenever we're trying to destroy we check right here if the currently authorized user is the owner of the survey but when we are trying to update we have done this in this update survey request authorized method okay so we have everything correctly set up now there are few classes which needs to be imported like this array for example array helper what else do we need let's scroll down below I think there is nothing to import however we need to Define an and I'm like question type enter so let's go under http and let's define right here let's define under enums folder question type in um dot PHP okay let's hit the enter so let's Define PHP text let's define namespace oops what did I do name space where is that okay let me just type it 98 03:26:49,160 --> 03:27:18,140 namespace that's going to be up backslash anums and then enum question type NM which should have a value of a string and then we're going to have the following cases like type text and type text area and type select and radio and checkbox okay if we Mouse over on this 99 03:27:18,479 --> 03:30:19,279 okay now vs code cannot actually understand that it supports nms okay that probably is coming from the composer Json or simply the extension basically is not very up to date but let's check the composer Json and our PHP requirement is set to 8.0 point something okay nums is only available inside PHP 8.1 so let's just change this into 8.1 and the error might also disappear okay it doesn't disappear but we can leave this because I'm sure it's gonna work okay so now generally I use phpstorm for working like on my personal projects or at work but I understand that not everyone has access to phpstorm that's why for this tutorial I decided to use vs code because that will be much closer to you than PHP store okay so we have this NM ready and we are using this and I'm inside the survey controller so if we didn't miss anything I think we have the controller ready we have these survey request ready store survey requests I think the only thing which is not ready is this survey resource okay so for now let's just make it easy and just return few columns like let's just return this ID and duplicate duplicate and return name and return slug maybe okay let's leave these as as it is right now and make sure that the data is returned as expected now let's go in the browser and let's try to add a new survey okay so we have this form already ready and however we don't make requests to the server side so if we just open survey View and we have on submit right here okay so let's try to make requests on submit and we're going to use axios client make post request the access client I think was not imported so let's just write import axios client from axios.js okay so we make a post request on survey and we're going to pass the data okay so at the moment let me actually pass right here a dummy data so we're going to pass a name 100 03:30:20,100 --> 03:30:50,479 actually it's called title so let's just pass the title here it's going to be lorem lorem ipsum okay what else do we have so we have description expired date and Status so let's give description to be test let's give it expire underscore date to be in the following format let's just copy this or let's just type it 101 03:30:51,720 --> 03:32:10,640 and let's give it status as well to be true all right let's see so even though we don't pass image and by the way image is required if we open if we open create or store survey request and your image is actually nullable okay let's try to make requests like this okay so I'm going to click save the request is made and let's have a look so a title to fillable property okay that's very clear error we missed this now let's open survey dot PHP survey model and right here we're going to create protected fillable array and right there we're gonna add title we will need a description there as well we will need expired date we will need status and maybe created it and updated it as well so I save this and hit save now field user ID doesn't have a default value 102 03:32:11,520 --> 03:34:00,899 okay so that's logical so we don't pass the user ID but now let's go in the survey controller because everything starts from here from store method okay we have a store survey request and we have this prepare for validation and we get the authorized user's ID and merge it with user ID and then right here we already have the user ID and it should have the it should pass the validation basically and if we go in the survey controller let's actually dump and die what is data okay so I'm going to hit save okay we don't get any kind of a response from here the dump and die that doesn't um basically I think Google chromebit doesn't show in output whenever you dump something and just exit so if I just return the data it might help us to find out so in the preview we get the user ID okay we have the user ID I think the reason we got the previous error was that inside the survey Moodle we have to add the user ID as well okay user ID needs to be added inside the fillable I hit save another error image doesn't have a default value let's specify right here image as well and hit the save another error image doesn't have a default value okay so it looks like images required and 103 03:34:02,040 --> 03:35:09,260 by the way we have a typo right here updated it okay if we go inside service table and have a look so we have the image which is basically required and when we make requests we don't pass the image that's why it cannot simply save that so let me actually quickly roll back the migrations and I want to reapply and make this image basically nullable okay so let's just run PHP Artisan migrate color rollback hit the enter okay so those migrations have been rolled back and now let's run PHP art design me great okay they have been applied and now if I just hit say right here okay 104 03:35:09,600 --> 03:46:21,599 what do we have I think the server is not running PHP Artisan serve let's hit this save we are going to have an error slug doesn't have a default value okay so here we have another error and what is the slog and why it doesn't have a default value so slag needs to be a generated from the title okay so for this we're going to use uh laravel sluggable package okay that is a very popular package from spotty and we're going to install that and generate a slug from the title okay so let's copy the following composer require paste and hit the enter and let's understand how we're going to do that so we're going to basically use the trade as a slug and then create method get slug options which will take the title and generate slack for us so I'm going to copy this portion and by the way the package was installed let's start the server and now let's open survey.php and down below I'm going to paste my code okay and let's move these trades at the top has slack and let's import this has slug we have to import slug options as well and right here we're going to generate slugs from title and save into slack so I save that and go in our server click clear up the network and hit the save so we're going to have additional error and find array key questions okay that's clear we don't pass questions from the front end but we expect that so from here we can pass questions equals an empty array okay so let's hit save again another error is no we don't have any error so we have status code 201 which means something was created and here is our output so we have ID we have a name and we have slack by the way we should not have name survey or resource it should be title let's save this into title and let's click save again and now we have ID slug in title okay and if we go in the database we're going to see under service table we're going to see three records okay we see and we see basically every information we we are interested in okay the expiry date is not populated we're going to debug this the image of course is not populated because we don't pass that but the basic saving of the survey actually successfully works okay and now I want to start working on either submitting the form and actually uh passing the image and implementing the full flow or first maybe display the surveys and then implement the form submission now let's have a look at the plane We are following so we haven't finished Implement survey creation we have prepared the survey controller on the larval side with resources and requests but the actual survey creation is not finished yet and the next step will be to create survey questions react component and the question editor and then we're going to continue to display all the surveys from the database instead of dummy ones pagination and so on okay so let's go again step by step and finish Implement creating survey okay with the image and the title and every every necessary information all right so let's open survey View and let's have a look in the browser so this is a review whenever we click on the change and choose them some image we need to display the image right here and we need to also pass the survey title description expired date and active to the backend when the request is made at the moment we are making dummy request right here so I'm gonna remove this delete this request and I'm going to remove this console log statement as well and let's start implementation from the on image choose so at this moment we need to uh we need to take the image so which will be so let's separate here an event okay and we're gonna get the event and take out files from there so let me Define const file equals event Target files at zero so I get the very first file so then I'm going to create a reader which will be new file reader oops file reader okay and then I'm going to execute read as data URL on the chosen file but I want to also add on load event listener on this reader right here I will get I will get a result but I think I can get the information from the reader as well so reader dot result will be the base64 string of the image which can be displayed in the uh in the view in the react component okay so right here in this state we have image and image URL so image URL is something which needs to be displayed so basically I'm going to call set survey right here okay so first of all we need to pass an object so first of all I'm going to destructure existing survey like this and then I am going to also give it image which will be chosen file and image underscore URL which will be reader dot result oops result okay and just like this I have the survey State updated and finally when I when I set the survey I want to reset the files even Target value so event Target dot value equals an empty string okay so let's scroll down below right here we display this image and we also check if the server image URL exists we display an image otherwise if the image URL does not exist we display this span okay so let me actually save this and have a look we might need to also open the developer tools go in the console so I'm going to click on change choose the image nothing happens let's reload the page but strategies and here we see okay so we have implemented displaying the preview for the image and we are also setting that image right here in the survey State okay so whenever we click submit and on that submit if we just console.log survey itself that survey will contain an image inside so let me actually click save and here we see survey and we have an image which is actually a file okay we don't need to send the image URL so we can actually delete that image URL before making a request okay so let me let's now try to implement a making request or let me first fill up some information lorem ipsum test description and let's choose some expired date and checkbox and click save okay now we have all the information we have description expired date we have title and status as well and the image of course okay now let's prepare the payload and the payload needs to be sent to the server so const payload equals and that's going to be let's destructure survey and create new object payload okay then on that payload I need to check if payload.image exists then payload dot image equals payload dot image URL okay why I do this because we implemented on the backend side that we're going to accept base 64 string for the image okay there are at least two options to send the image to the server side one is to create the form data and send with the form data the actual file the second is to convert that file into base64 string and send it as a part of the Json okay we're doing this second at the moment and now I have the payload and on the payload I going to delete the image because I don't need the image I'm sorry I want to delete image URL okay I don't need the image URL I'm just sending the image because I'm accepting that image on the server side and then I'm going to call axiosclient Dot host the URL will be survey we're going to pass right here payload a load then we accept the actual response or um I think it's a response yeah we get a response right here and then let's just print console.log the response okay what is this let me format the code save this and let's have a look in the network as well and click on Save okay the request was made 401 okay I probably need to reload the page okay so this is something which we should probably fix okay so at the moment might how can uh returns with 400 and one which means that my token is not valid okay and if I go in the surveys and create new again choose an image test here and let's click save okay so this returns 401 and now I'm redirected to the dashboard which is not actually correct okay and if we check also in the console we see this 400 watts so let's now check axios file because I should be redirected to the login page whenever whenever the server returns with 401. 105 03:46:21,600 --> 03:47:19,880 okay let's see so let's check this part debugger let's save it go into surveys and try to reproduce this problem once again let's fill up with test test here and let's click save okay so we got the response it looks like that the status code is 401 and logically we should be redirected to the login page but we are not and why I know why because we the application tried to redirect us to the login page but inside the login we actually check if let's open logging log into js6 we check where's the check let's have a look 106 03:47:21,540 --> 03:47:27,439 okay I think we don't have that check right here 107 03:47:27,899 --> 03:50:41,779 so for some reason we stay on the dashboard and we need to understand why we stay there obviously because in our state we don't clear up everything so in our state there is still there is still the token which is which is invalid token and if we check the local storage so we have the token right here so at this stage so we need to delete the local storage okay we don't need that and also if we check state provider context provider right here we have the set user token and we have the user token which actually is the value from the local storage by default okay but this is the take so even if we clear up the local storage and run delete item for the token that user token will still be there and it will still have some value okay so we need to take care of this okay so I want to test one thing uh whenever the whenever we just redirect user to the login page why we still see the dashboard this is something I am interested in we see that the URL changes but we are not actually on the login page if I just reload I'm redirected to the dashboard if I try to go into logging I'm redirected to the dashboard I think I know why because in the guest layout we check if the user token exists we redirect user to the slash okay this is uh this is something we need to consider and the user token basically doesn't delete so if I put debugger right here then go in the surveys and try to create new one and hit the save okay here we see one debugger let's continue and here is the second one and the user tokens still exists even though this is invalid so we need to clear up this user token okay and the simplest solution I'm going to do I know there will be a better solution but the very first thing that came to my mind is that from the local storage okay I'm gonna delete item token okay and then um I can just reload the page okay this is a bad thing I know for single page applications but this this is the very first thing that came to my mind so window location reload okay and we comment this out okay and now let's have a look so we proceed let's go into surveys create new and hit save okay now let's see what happens so local storage delete item in the function okay why is that a function local storage 108 03:50:42,180 --> 03:55:09,680 uh how it's called remove item a bit so we need to remove item okay now let's click save and now I'm on the login page if I continue this I see the login page let's remove this debugger from the guest layout and we don't have debugger anymore from here so if I now reload IEM on the login page okay if I just have a look in the local storage I don't have anything right there however I'm gonna set item token once again let's try it token will be one two three let's hit the enter now let's open dashboard and I'm on the dashboard page because I have a token and the token is available okay so this is something we need to also fix the token is not valid there is some kind of token and we see the dashboard but but very important thing so we should we see actual HTML and JavaScript but we don't see any content no request is made on the server okay if we go in the surveys page at the moment we have dummy surveys but in the future when we Implement actually loading the surveys and when the request is made to the server to get that surveys user will not be able to see the service server will return 401 and then user will be redirected to the login page okay Let's test this so I'm going to try to create new survey hit the save button and I am redirected to the login page so right now as I mentioned it's not the ideal solution right now I call Window location reload uh for some reason router navigate doesn't work if you know how to make this working without window location reload just let me know about this in the comment section below I don't want to make research right now um about this I'm a little bit lazy at the moment okay and yeah this is just works and it will work I'm sure so let's leave it as it is right now and focus on creating now creating survey if I just go on the surveys now I have a valid token click right here then let's upload an image let's give it test test let's give it a date and let's click save now request is made we see response for uh 201 we get the ID slog and title okay we need much more information than just ID Slug and title but this actually is a proof that we have just created a new survey let's give it lorem ibsum as a title let's click save and we see right here lorem ipsum title and Lauren ipsum slug perfect now let's Implement redirecting user to the surveys page whenever the survey uh is created so if you go in the survey view right here I'm going to write navigate and that needs to be navigate that needs to be imported from react rotor well actually let's move up and right here I am going to create navigate which will be use navigate and let use navigate will be imported from the react rotor Dom so I can this navigate and then right here I'm going to pass it um service okay I think that's the path for the for the service let's open router and right here we have the service okay I think that's good so now if we go in the service and choose some image give some title and click save the survey is created and we are redirected to the survey list page okay and let's test once again creating survey will with all the options we just provided so I'm going to give it survey one let's choose some image we give it test description one let's give it today and active and click save 109 03:55:10,260 --> 04:06:27,479 okay we have some kind of error and the error tells us expired date must be date after today okay we need to choose something in the future so I'm going to choose tomorrow and click save by the way we need to also display the validation errors okay so if we go now in the database and click on the react survey 2 because this is the database we are using at the moment and I'm going to click on surveys and the very last one let's show all of them and the very last one will be survey one test description we have the created updated and the expired date is null okay so this is something which is not handled properly and we need to fix that we need to check that and fix that let's check on the client side if we send it correctly go in the payload we send the expired date okay it looks like that we are sending this properly however we sent it we sent these as no this is the first one and the second one we send this as tomorrow okay so that should be saved let's check this once again give it test test let's choose this first of December click active save that the date will send reload the page right here and the expert date is now okay let's now go in the back inside and let's open first let's open survey.php and check if we have expired date we don't have the expert date right here it's expired d okay so now I save this and let's test creating survey once again to make sure expiry date is saved properly test test choose tomorrow active save go into page from my admin reload and here we see tomorrow okay so we have successfully saved surveys and we have also images right here okay so I think that's perfect let's have a look at the plan again so Implement survey creation I think we did that and now I think we can start working on the survey questions react component uh however let's also Implement displaying validation errors okay inside the form I think that's going to be really interesting for this let's try to make requests which will return errors so let me actually um let me skip an image and let's keep everything empty and click save okay we should get some kind of errors and the errors tells us that the title field is required okay so and we need to display this somewhere we can display this uh all errors basically at the top of the form or we can display this under this input field okay so let's try to make it simple and I'm going to open the survey View and right here above the about this D maybe I'm going to create I'm going to create a div and let's give it class name BG red 500 now let's give it text white adding Y2 I think three and rounded rounded LG and let's give it some text like lorem ipsum just few words like this let's save this and have a look okay so this is our error okay the positioning is not ideal so let's get this and put inside inside this div element and it has its own padding let's format the code save this okay I think this looks better let's increase the vertical pining into three and I think that's good I think that's good so I don't like this rounded for this one so I'm going to remove it okay perfect now let's display the error message we get right here okay so we have a general message the title field is required and if I just provide the title and click save what happens next the survey is actually created which is perfect however if I just provide title right here and if I choose the date to be preview State older than today click save then I get another error the expiry date must be a date after today okay so this is perfect if we just go in the whenever we make a post we have then and if I just add H right here we get the error okay let's print the actual error right here and the error should probably have a response so let's actually let's actually print error and error.response okay so we say that and go in the console go in the info clear up everything and click save okay so here we get the error which is axios error and the error has response right there okay here's the response and the response has status and data and the actual data is what we are interested in data message okay let's do like this if error if error exists and if error dot response exists then we need to take the error so const error equals error.response dot data Dot message okay and let's create a state variable right here which is going to be for the errors const error message equals or we should do it like this let's just call this error okay and set error equals use state and the default value will be an empty string okay now let's scroll down below here we have this error message and let's just outputs only if the error is set now if I format the code save everything I don't see this error message right here I click save okay we got the response but we didn't set the error okay this is something we need to do right here so I'm going to call set error and I pass the error or we can simplify in pass error response data message so I set this and now let's click save once again and here we see the error message however this displays the lorem ipsum so if you scroll down below and we're going to Output right here error so I save this again and we see title field is required I provide the title I provide description I provide expired date but I'm going to provide it past date and click save now I see a second validation error the expired date must be a date after today okay so this is how we can easily display your messages but if you want to display each individual error message below this input field I'm going to give you a hint on this and leave this to you as a challenge so let's observe the actual response what we get so we have data and the data has errors right there and the errors contains expired date so what you need to do is to create a state right here which is going to be errors state in the plural form or you can call it even server errors and the server errors errors will become let's zoom in it will become the following object okay and well it will have expired date inside there or title now if we go in the code below each individual field for example below this survey title or below this expired date you're going to create right here probably a small element which will have a class name text red 500 and inside there you will have lorem ipsum something okay and this one will be a red error message displayed right here if you want to give this input field also red border you're going to give right here class border oops border red 500 and you save this and we have the Border rate 500 and basically conditionally you're gonna check if inside the errors you're going to describe right here object of Errors if the errors has expired date inside right there you're going to conditionally add the Border rate 500 cost to this input and you're gonna display this small only in that case when the errors for expired date exists okay in fact you're going to display your message right here okay this is a hint not a full implementation I'm going to leave this challenge to you I'm going to undo the changes I made right here okay and we have error displayed at the top of the form which is good enough at the moment and let's create once again a survey and click save and and we go there because the expiry date must be date after today so I'm going to choose in the future and boom so we have just created a survey now let's create survey questions component but let's assume that it already exists and we're going to use it down below the form input field so we have those input fields and at the bottom of the active we're going to use this survey questions uh component right here but let's actually Define it under components I'm going to call these survey questions Dot jsx and let's generate a functional component it has the correct name survey questions let's save this let's remove this import and if we go in the survey view let's use right here survey questions and 110 04:06:28,199 --> 04:28:24,260 and that's it so let's have a look now in the browser go in the sorry creation and you see survey questions right here okay so that is the basic component let's go in the component that is the basic component and now let's start working inside that component first of all let's create a template and I'm going to create fragment and inside the fragment we're going to create a div wrapper for every everything inside the component okay so and then um then we're going to have a title for the questions and we're going to have a button Talon says pattern and the pattern will have an click event listener which we'll call add question function that it question function doesn't exist yet and we're going to create all the functions after we create our template okay then down below we're gonna give it a icon and the text okay and then I start iterating my questions so I check first if the model questions length exists then I start mapping each questions into js6 component and in this case I assume that I already have a question editor component which we're going to create soon and the question editor component will be responsible for actually displaying the input fields for the question like the question name and question type and question description okay and this question editor will have a key and index and the question object itself and we're going to also listen to a few events on this question editor whenever the question is changed whenever for example the title is updated whenever uh whenever the question is added basically in this question editor we're going to also have add a new question button and we're going to listen to this as well so we're going to have also delete question a button inside that editor and we'll listen to that as well and in the else case we simply display a text you don't have any questions created okay and now we're gonna start working on creating those functions question change add question and delete questions so for this let me move up and let's create those functions right here first of all let's define uh two props survey and on survey update because we are actually passing those props um necessary question so we we are not at the moment passing those probes but we need to pass and we're going to accept the actual survey right here in this survey questions component and on survey update we're going to call the following method okay so locally I'm going to create a modal State and the module state will by default will be the given survey okay and then let's define add question inside eight question we're going to call set model we basically give the existing model and the structure that and then we add questions to be an array okay so we are adding a new question inside the model okay so we are going to give the structure existing questions module questions and give it and then we're going to add a new question for a new question we're going to have the following following schema like we're going to have an idle ID which will be newly generated uuid for this we're going to install and use the uuid package okay the default type for the question will be type text the question will be an empty string in the description will be an empty string and data will be an empty option object okay and just like this we have this add question ready next will be to define a question change inside question change we accept the question right here and we check if the question doesn't exist we immediately return with empty string with nothing with a void then we we need to update the questions right so for this we start iterating over model questions with the map method and we are checking if the each question ID equals to the given question ID this means that we have to update this question and we return a new object with the giving question as a structured one so we create new object however if the question ID doesn't equal that then we return with the existing queue okay so whenever the question ID equals that we have to update it otherwise we return the original one and down below we have these new questions and again I'm going to call set model give an existing model and then I'm going to give it questions correspond to new questions as well okay and let's create delete question as well so we accept the question right here first we call a filter method on module questions and we we filter all the questions which has ID different ROM the given question ID okay using this method we are sure that inside new questions we will not have this question ID then again I'm going to call set model give it a model and the questions which will be new questions and finally we're going to listen to the modal change using use effect and we're going to call on survey update whenever model is changed we call on survey update which is a prop received right here in the parent component will know about this and we'll do all the necessary things that is that it needs and at the top of the component we are going to import the plus icon because we are using that inside the template right here we're going to also import react we're going to import use effect we're going to import use State and we're going to import the V4 as a uuidv4 from the uuid package okay and down below we're going to import the question editor let's assume that question editor already exists but it doesn't not exist at the at the very moment okay well I think this react component is not necessary because that is automatically generated by these um RFC keyword shortcuts so we can even remove this react component okay now let's do two things first let's go into survey View and we're going to pass right here survey to be our survey and we're going to pass also on survey update to be our own survey update and we have it on survey update Define somewhere I think we don't have it defined but we might need to Define it somewhere okay so let's save this and let's scroll up uh probably below all the functions let's collapse this on submit below right here we're going to Define on survey update we are going to accept survey right here and then I'm going to call set survey and we're going to destructure the accepted survey and give it inside the survey okay and just like this we have it on survey update let's bring up the terminal okay we have a lot of Errors especially on uid so I'm going to close this uh kill these and I'm going to run npm install Dash uppercase s uuid okay and and then whenever this is installed we're going to run npm run Dev we should not see any errors anymore which is good now let's go in the browser let's just reload the page and we have an area about the question editor which is very obvious we don't have that component let's go in the components and create new file question editor.jsx let's create functional component let's remove this react and let's delete this template and now let's start working right here first of all let's import a few functions so we will need use effect we will need user State and we will need use State context right here then we're going to accept props we're passing those props from the survey questions do you remember so we are passing them from here so we accept the index we accept the question we're going to accept add question which is going to be a function we're going to accept delete question and question change okay and then we're going to define a local state model which will be a question by default is going to be the given question the structured one okay then I'm going to Define also question types and the question types does not exist in our state context yet but we're going to create that inside the context provider soon okay then I'm watching on the modal change and whenever the question is changed I'm going to call the function question change notify the parent component that the question was actually changed okay and down below I'm going to create one small helper function which I will use in the template that's going to be uppercase first I accept the string basically using this approach I'm going to convert the type types first letter into uppercase and it's a very easy function so we accept the first character at position 0 call to uppercase and then I'm going to take the everything else after the first character okay okay so we have the functions functions ready let's now open context provider and first of all let's define right here question types for auto completion purposes is an empty array then right here I'm going to Define const question types and we're gonna use hate and let's give a few question types like text we aren't going to implement all of them right now but you will get the idea based on a text example and I will leave this as a challenge to you again so we're going to have uh select we're gonna have a radio we're going to have check box and we're going to have um text area okay so we have all those question types and obviously from here we need to give the question types so we save this and now let's go in the question editor and let's start working on the template now let's define wrapper component wrapper div element and we're going to give it flex and justify between in margin bottom and then we're going to accept we're going to print out the index plus 1 because the index will start from the zero and the modal question the actual question text and now let's start rendering uh the title and buttons and everything okay so first we will need the add button which will have obviously Talon CSS classes and it will have an event listener on click on click we're going to call the add question function in the add question function is given right here okay then we're going to create another button which will be delete button which will have obviously its own tolerances classes and it will have its own click listener in which we will call the delete question okay then we're going to create a div for the title and type and everything okay inside there we're going to have the question text part question text HTML element and then this will have a label the question itself and the input okay the input will have a two-way data binding so we give it a value and we listen on change and we call set model and we pass the whole model as well as the question which will be even Target value okay every time we type something inside the question it will update the model okay and we want the model to be always updated okay and down below we're going to have question type uh which will have uh which will be a select type of element it will have obviously its own classes and ID and name but will it will also heavily change event listener okay and now inside the select we need to iterate over the question types and those are the question types we defined in the context provider right here okay so we start iterating over the question types and display an option which will have a value of the given type and it will have also a selected property based on if the current type is the same as the modal type okay and we obviously output the type but this is the case we use uppercase first so we convert the first character into an upper case and in this case the T will be converted into uppercase s will be converting to an uppercase R will be converted into an uppercase and so on okay and just like this we have the question type down below let's create description with a label with text area and the text area will have two-way data binding we accept a value and we listen on change and set the mode and just like this we have the question editor let's go in the form and right here look at this so we have the questions left side on the right side we have the button if I click on the button we obviously have an error because we didn't import some things so we created right here plus like we used basically plus icon and trash icon so let's actually delete the last character and let's import this from outline and do the same thing for trash icon control space and outline so those two icons we are imported and now let's have a look let's just reload the page and click add question and look at this okay so this is the first question if I click add again it's going to create second question and each question also question editor component has its own add button okay and when we click on this it's going to create another question let's actually write here question one okay and that is question two this is question three and so on and whenever I click add question it's going to create one additional at the very bottom I can click on delete and it's going to delete that if I click add right here it's going to create this one at the very bottom as well however we can improve this we can go even step further and whenever we click it right here it can create question in between the question one and question two as well okay so that's going to be also very interesting and challenging uh let's actually do this or I can leave this as a challenge to you if you want this to be a challenge to you pause right now the video okay and try to make an implementation on your own so again whenever you click add button right here it should create new question in between the question one and question two after the question basically uh you click that that button if I click add button right here on the question two it's going to create new new question after question two but before question three at the moment it always creates question at the very bottom okay again pause the video if you want to implement this on your own try to do it on your own and then continue and see my solution okay how I'm gonna do this I will go in the question editor and right here I have this I have this Aid button okay and whenever I call a question I will pass an index okay uh let me actually convert this into an arrow function where I will call eight question and I will pass Index right here because I have index everywhere right I don't even probably need to do this to Be an Arrow function okay let's do it like this now eighth question this eight question uh calls the parent add question okay let's go to the parent and understand it so we have a question right here and every time this is called it's going to create new question at the very bottom okay so what we can do is to accept an index right here okay I want to add new question on that specific index and then we need to split that array questions array okay and put that question we can use even supplies for these okay let's let's actually try to do this okay so modal questions we're going to run splice on that index we're gonna add the following object okay and then down below we are going to take the modal questions destructure it and assign it into questions okay we need to accept this this index and by default let's um okay let's write index equals either index but this index might be in zero as well okay so we need to check if index does not equal to undefined if that index was given then we take the index in else case let's put the question mark in else case we're going to take out the modal questions a length minus one to put this at a very last position okay uh or it can be even the length when to test this so now we have the index let me put a debugger right here as well and in the question editor we call this eight question however we need to pass index again so let's change this back into an arrow function and then I'm going to execute this and pass index okay now I say this and I have three questions and let's click it right here so debugger comes right here the index given is zero so I want to add a question at zero position no the actual correct one will be to add a question at zero plus one position so I'm going to change this into index plus one okay this is the position I want to create a new question okay let's proceed and nothing was actually added probably we even have an error some kind of error we do have this error but let's actually let's actually try to reproduce this error again click add now the question is one we're going to add this at position one and then let's step over let's actually continue and we don't have we don't have any error at the moment but the question was not added let's reload the page okay I'm gonna add let's add a question okay the adding question does not seem to be working at the moment let's go in the questions okay what is module questions let's click it right here model questions is an empty array and at position white position and position first which is not logical obviously at position first we are adding something right now this one is not a position this is an event okay let's scroll down below because we have ADD question right here as well okay let's convert this into a neural function and call add question with undefined or with zero okay in this case if I just reload the page and click at question the index right here will be zero so I want to add a question at position zero and if I proceed and while it doesn't still create that question which is which is strange so let's actually create a question again let's step over a few times and the modal questions 111 04:28:25,260 --> 04:30:24,080 okay at position zero it's try to add okay let me let me check uh JavaScript splice because I think I think I think I know the reason so the supply is basically accepts first the index second how many elements you want to delete I want to delete zero elements yes start then delete count and then we have possibility to add other elements okay I think this is the this is how we should do it how we should do it and let's just reload the page again and click add question and proceed and the new question was added okay let's give it a question one let's create another question which will be which was added at the very first position not sure if this is correct let's click add question again and we accept right here position zero okay this is not so good let's have a look so we're passing right here zero now we don't know zero let's remove it it should add new questions at the very bottom so we have now three questions let's delete and click add question and now it added the question at the very bottom okay this is what we wanted go in the console we have an error let's just reload the page click add question proceed this is the question one click add question proceed this is question two however we still have this error let's have a look default value warning use of default value or value props on select instead of settings selected an option 112 04:30:25,260 --> 04:30:59,120 okay let's have a look challenge list should have a unique key prop check the render method of question editor okay let's go into question editor and we are iterating our options but it doesn't have e-rate here okay inside the key we can provide the same type okay we save that and just reload the page click add question let's disable the breakpoints for now 113 04:30:59,460 --> 04:31:04,520 we still get this error default value 114 04:31:05,100 --> 04:32:18,620 or value props on select instead of setting okay we need to find out this according to the error it probably means that right here we shouldn't have selected but we should have a value okay if I just remove it we should not see this error anymore let's test this okay we don't see this error anymore which is which is excellent so let's just test the functionality so question one and I'm going to click add on this question on the question first click add and not sure where it created it so let's just create question two and click it right here okay now look at this so it created new question after question one but before question two and this is exactly what was our goal okay and we actually did that now let's test if the questions are actually saved in the in the database so let's go in the network 115 04:32:20,279 --> 04:32:58,439 and let's choose an image give it test let's leave everything empty and I'm going to click save okay let's have a look so we have validation error okay type the selected type is invalid let's go to payload and we have the questions and the questions have data type question okay everything looks good and the error tells us the selected type is invalid 116 04:33:02,279 --> 04:34:18,539 okay we have the selected type to be text now let's go in the survey controller in the backend side and right here we have this question and the optional the possible values for the question will be question type NM and the question type num think does not exist so if we go in the app http enums we have we have question Type n however opening this using control didn't actually work so we have this imported properly I think we don't have this question type and I'm imported properly so let's hit alt and enter no code action is available okay let's just try to try to delete few characters and then control and space and now it detects and autoimp tries to Auto Import let's hit the enter and let's now have a look okay that was no that was not imported 117 04:34:19,980 --> 04:34:55,641 question type in them here it is it was Auto imported let's we should see a different error by the way we should not see that if the question type NM was not imported but let's try to hit the save again and we should probably have the same error let's now open question type NM and we have text and text area and select and radio and checkbox and so on okay so what is the problem 118 04:34:57,359 --> 04:37:58,699 so right here we give it type to be required and we're using NM and give it question type Anna after a little bit of research I found that many other people actually have the same problem so they switch to using nms and we have backed nms as well with the type of string and it simply didn't work and they turned into Ruby they started again using uh rule in where they are passing the uh okay and error as a cases of this uh of this NM okay this is something we can do right here I hope that this new NM would work but for some reason it doesn't work okay so we what we need to do is probably just change this and execute rule cruel in and we're going to pass we're going to pass few options here so we will need text we will need question well we we need to take the value from this text okay let's actually put this a new line and like this okay and we need to take a value out of this and let's duplicate this few times and what options do we have we have text area and select and radio and actually I want to rename this okay I want to rename that symbol and just call this text like this so when I hit the enter it should rename everywhere okay and by the way this is done using um using the extension called PHP tools okay so we need text right here we need text area and we we have to rename this as well so let's just rename and call this text Aria we have select we have radio and we have checkbox okay so then here we have text area here we have select here we have radio and here we have a chat box we get all the values and then we run this in the rule in now let's execute this and have a look okay so having their question type and I'm not found the class not found so let's try to import this if it is not imported up a M's question type NM what's the problem question type am 119 04:38:00,859 --> 04:38:04,760 question type in 120 04:38:10,020 --> 04:38:17,600 okay I think we need function uh sorry we need an area annotations here 121 04:38:19,799 --> 04:38:35,140 probably like this so let's have a look click on Save okay so let's have a look in the trace that's coming from the survey controller line 58. 122 04:38:35,141 --> 04:38:53,900 line 50 8 from here okay then we have question Type M is not that class imported I think it is imported question type NM so save this and click on Save 123 04:38:55,980 --> 04:39:04,980 okay we have an exception survey controller line 220. 124 04:39:09,480 --> 04:39:22,160 where is that it's right here am I doing something wrong let's have a look so we have rule in then we pass 125 04:39:22,859 --> 04:39:33,500 well we're passing right here values but we can pass names if we want 126 04:39:33,959 --> 04:39:42,080 let's try passing names we don't need actually names the problem should be something else 127 04:39:42,420 --> 04:39:56,480 is the rule imported let's have a look we have illuminate validation rule okay that should work 128 04:40:00,180 --> 04:40:03,980 okay we're gonna find this out 129 04:40:04,440 --> 04:41:05,900 let's change this let's actually comment this out and click on Save okay selected type is invalid let's specify right here text save this and click save Okay add question to fillable property to allow Mass assignment okay this is something we probably missed if we go in the survey question right here we're going to add a fillable protected variable so let's add it right here we need ID type question description data and Survey ID inside fillable and now if I click save I see column that's found survey ID and non-commerce reading field list insert into sorry questions question type description survey ID okay did we miss again something else if we go in the 130 04:41:06,540 --> 04:41:17,120 if we go in the database migrations and have a look in the survey questions 131 04:41:17,780 --> 04:41:30,378 so we have this survey ID if we check now inside the database for the survey questions 132 04:41:31,740 --> 04:41:34,760 what is this 133 04:41:35,458 --> 04:41:44,540 what is this what is this okay I feel guilty 134 04:41:45,240 --> 04:42:08,940 okay what did I do so the boring ID here should be the survey ID so we need the following ID which references on ID references to ID on surveys 135 04:42:09,958 --> 04:42:45,900 on surveys table right this is what we need to do uh okay let's check the other migrations foreign id4 that's that is what I missed so there are basically two approaches for an ID for the model and then the column name the second approach is just to use for an ID okay in this case we can leave this as it is right now or undo it and just fix that stupid mistake right here foreign ID 4. 136 04:42:45,901 --> 04:45:52,400 okay however um however the immigration is already executed that migration is right here so this is something very stupid mistake uh that should not be here so I'm gonna do I'm gonna just roll back all my Creations so PHP Artisan immigrate colon fresh okay so everything was dropped and recreated and let's run PHP Artisan uh serve okay let's check now in the database uh sorry in the in the browser and basically at the moment we are logged in again which is something we need to win to fix and if we just open the plane We are following so uh we are right here create a survey uh quit the question editorial component and basically we need to test also saving that but one thing what we need to do is to log out on page refresh if the token is invalid okay this is something what I need to do and at the moment we're going to run localstorage.clear well I can click on logout I think we have that as well we are logged out and I cannot log in with the current user because I actually deleted the database and if I just uh refresh this we should see serviate right here okay it's perfect so let's now login with the username and password and click sign up okay I'm logged in go in the service at the moment we have Dam service right here create new one and let's specify test some description and let's click to add a question okay so by the way I noticed one small bug whenever we had a new question it deletes the survey title if I populate the survey title it actually deletes that okay so let's provide test right here this is something we we're gonna fix this as well and then click save okay now that was created and let's check inside surveys we have one record any sensory questions as well and we have one record right here as well however we couldn't make it working with the enems let me close the migrations and if we go in the survey controller we just specified right here a text now if I uncomment these text and value which must be string okay this must be string and let's create new survey that was deleted again and give it a test and I'm going to click save okay these returns 137 04:45:52,860 --> 04:45:56,780 sorry these returns 138 04:45:57,240 --> 04:46:07,580 okay class up a M's question type and I'm not found 139 04:46:07,980 --> 04:46:10,878 if we scroll up 140 04:46:11,160 --> 04:46:17,780 up a M's question typing so we have up 141 04:46:18,378 --> 04:49:42,020 HTTP nms we have up http nms up HTTP backslash enums well we probably don't need that under HTTP so this is something which should be outside like this now we have up enums correctly okay this is how it should be and if we go in the survey controller we now need app enum's question type in okay that is something that was probably causing errors now let's have a look so I click on Save and the survey was created now if I go in this survey controller and check this part now that worked okay now I have a feeling that this should work as well so I'm going to copy this and change rule in into the question type enemy gain so I saved it and try to add a new survey so let's give it uh okay this this part gets annoying I'm going to give it some text question one whenever we change something in the question the survey data is lost okay so let's just put this right here and click on Save and now the survey was created so we have a we had um two or maybe even more very stupid mistakes so first is that we had something very bad written in Immigration uh it was a typo okay let's let's be honest so it was a typo I wanted to write uh the 1494 but let me say currently write foreign ID which actually actually created a column with this name okay which is uh which is funny now the second thing is that the question type NM which had a namespace app nms was created under up HTTP nms folder and that was not visible and because of these in the survey controller this validation rule did not work properly okay and now this rule works fine and again I want to create now uh like a survey one this will be deleted okay so let's fix this so this should not be deleted now let's open survey View and we're looking for the on survey update let's put the debugger right here and let's type title here and then a new question okay that was lost why was that lost and that happened when we add a new question okay that comes from the question editor let's oh let's have a look what files how we have the survey questions and you said sorry questions we have we have 142 04:49:42,718 --> 04:51:50,660 eight question okay so right here inside the modal questions we append then we take the model and we call the set model and is that all and that actually updates the model and whenever the module is updated we call on survey update but it looks like that this is not triggered because this answer re update is added from the survey View down below and that is not executed let's see if we have breakpoints enabled let's go ahead and Source now we have breakpoints disabled okay let's type some text here and click add okay now here it comes let's continue and we have a second breakpoint we accept the survey okay and that survey didn't doesn't have any kind of title and that's why well the actual survey has title but we lost that information okay so we have that local survey right here isn't it we have the survey and we accept survey rate here as well okay let's call this just s and I want to see what is actually s and what is survey so S at the moment is empty let's proceed and let's type some Title Here and let's click add question now let's continue and here we have S which probably has single question inside and we have survey as well and that survey has a title inside there okay so 143 04:51:51,240 --> 04:52:28,798 okay we need to think so we have two objects and we need to merge them into one okay let's debug one thing we are passing that survey uh survey variable from here into its children and right here we have the survey questions and we're passing that so if we go in the survey questions and let's actually print uh let's actually print this survey so I'm going to run Json stringify 144 04:52:29,540 --> 04:52:56,580 survey let's specify undefined right here and two so I save that and we probably need to put this in a pre-tag so I save this and just will reload the page I think we need to remove the debugger so let's remove it from here and 145 04:52:57,298 --> 04:54:29,240 from here as well okay so what do we have so we have title slog let's just populate something test okay that is populated if I click add question that disappears okay that that is also logical but if I start typing here something that is again populated okay so it's very obvious that inside the survey questions when we print the actual survey it gets updated whenever we type something in appearance okay what is model because the model is a new state created out of the survey okay what is the model let's just roll the page and type test okay this is something this is something that doesn't get updated and this is something we need to fix so the model is taken from the survey once and then whenever the survey is updated model is not changed which we should probably do is to watch at the survey change and update the model as well okay so if I just duplicate this use effect and watch survey change and we call set 146 04:54:29,700 --> 04:54:32,420 model 147 04:54:32,940 --> 04:56:24,600 the structure the survey and assign it into modal so this change probably was a mistake because right now we are listening to the survey update and whenever service updated we're updating model but we are also listening to model update and whenever module is updated we are emitting a parent hey that the survey has just been updated and we update we pass the updated model but on survey updates the actual survey this survey which is given as a prop is also updated so whenever this updated this function is called whenever this function is called uh the survey is updated and then this final function is called and we have an infinite Loop okay if we have a look right now in the browser we see a bunch of Errors right now coming in the Chrome console and as we observe we're going to see that the errors are basically a maximum update depth exceeded so what we should do we should comment out this last part and maybe make a modifications right here so let's have a look so if we just reload the page we don't have any errors at the moment but we have to actually convert this and we have to fully understand what's going on right here so here is where I'm thinking the survey questions component except at the moment f function called on survey update but as far as these components is called Surrey questions it should not really care when the survey is updated it should only care when questions is updated because we're going to have kind of like two-way data binding for questions itself so what if I modify these on survey update and call this own questions updates 148 04:56:26,100 --> 04:59:17,400 like this and then down below whenever or we have a use effect so whenever the model is updated I'm going to aim it I'm going to call this on questions update but I'm going to pass modal DOT questions okay now let's go to this review and we have right here survey questions so in this survey questions component let's change this on survey update into on questions update and the function let's rename it and call on questions update hit the enter I think it was renamed down below as well and we're going to assume that this one will not accept right here sorry instead this will accept right here questions so what would we do right here is that we're going to destructure the existing survey which we have right here so let's take the existing survey survey and oops and then we are gonna update its questions okay and if we go in the survey equations I think this looks this looks correct so let's save this and have a look now we have this object this is a survey object and we have a title right here so whenever we change the title like test scroll down below we don't see that a title updated right here okay so from here in to child update doesn't work but let's try to add a question and as we see let's reload the page I don't like errors on the right side and click add question and that was added in a survey that was appended okay let's give it a like one for example then click add and we added second question which is two okay however we also want that whenever we have we type something right here test for example this model should be updated okay and this module by the way is printed from here okay this is the model okay what do we need to do in this case okay let's start from the survey View and have a look so we have right here title and let's see input we listen on change we get the updated title we call set survey and we destruct your existing survey and we update the title and that set survey should update the survey let's take this survey right now and print it right here Json stringify 149 04:59:17,878 --> 04:59:30,320 pass the survey undefined I think I should have created code snippet for this undefined and maybe two so 150 04:59:32,218 --> 05:08:14,660 I need just one curly braces so I save these and here's our survey now if I type something right here test does this update the title yes it does so it correctly makes the modifications right here let's specify some description and the description is also update this is not passed down to the model which is printed right here so why the survey object is passed to the survey questions from here now if we go into three equations we accept survey right here and we need to listen to survey change and whenever survey change happens we're gonna update the model but we also listen to the model change and whenever module is changed we update the questions which is something probably not we want let me think so we don't actually need this use effect because this use effect I'll just listening to the survey change in updating model is not necessary because we don't need model in this component what we need is model questions right and we do have model questions and the thing is that the model questions basically cannot be changed from outside so if I just comment this out and have a look so we have the model right here and we don't actually need as I mentioned the model itself so we can even modify this and if we go in survey view instead of passing a survey from here we can pass questions and then listen to the questions update so let's change this into questions and we pass survey DOT questions now if we go in this component instead of survey I'm going to change this into questions so we don't need this model right here what we need is questions and whenever questions are updated we're gonna emit these to the parent okay and this happens in few places whenever a new question is added or whenever a question is changed or whenever a question is and delete it okay I'm going to actually comment out this part as well okay and let's implement this hundred percent correctly as it should be so now we have questions right here and we're going to have a bunch of Errors so I'm going to comment out this part the the modal part basically or maybe I just pass an empty object so I don't want to have any errors let's scroll down below and right here I'm going to print out questions so if I say this uh we obviously have an error and that comes from the Country property the find the find length so somewhere we used modal DOT questions length I think this comes from here so let's let's change this these are questions given as a prop now I'm going to create an internal questions state so let's call these my questions and we're going to have set my questions as well and the default value will be let's give it the structured questions so I create a copy of the giving questions and create my questions state now I'm gonna comment out everything from inside these functions like this and like this and like this okay and down below we have the questions and I'm going to print out my questions and we also have modal questions which is not necessary I'm going to print out my questions.length and then iterate over my questions and print them so if I save this and have a look in the browser okay let's roll the page I don't see any errors in the console which is good we have empty questions array and if I just click edit button nothing really works because we haven't implemented that part now let's scroll up and work in this aid questions so what do we need to do we need to detect the index based on my questions.length and then inside my questions we're going to add on specific index new question and then we call set Moodle which is something we don't need we have in my questions or maybe what we should do is called set my equations instead of set models okay let's do this I'm going to call set my questions and we are going to destructure we are going to the structure my questions like this okay so I think this is this is good so let's say this and and one additional thing we can also call on questions update to notify the parent that hey questions have been changed otherwise we're going to have different state outside in different state right here let's test this if we go in the survey view let's print right here I'm going to copy and paste these pre-tag and put this and then I'm going to print just questions or it should be like survey DOT questions okay so I save this and now we have questions outside in these survey view component and we have questions inside these question survey questions okay and when I click add look at this so the inner state is updated but the parent outside state survey questions stays the same now we need to go in the survey questions and whenever new question is added we're going to call update questions or on questions update and we are going to pass my questions okay now when I save this let's just remove the page click add now look at this so the inner state is updated but the outer state is also updated because we call this on questions update and we listen on questions update right here get the questions and update the survey and whenever we print this survey DOT questions we do a print right here we get the updated questions which is exactly what we want now if we go in the survey equations we implemented that questions change should be pretty straightforward so instead of model questions we're going to have my questions then instead of calling set model we're going to call set my questions and we are going to pass my questions or we should Pass New questions that's more correct and now we need to test this part as well but we also need to call on questions update and pass my questions so I save this and now let's roll the page once again and click right here so both areas are the identical and now whenever I type something in the question input field and that should be changed but it also should change the parent components state so test one let's scroll up here I see here I see something different not test one okay so we get the state a little bit late because right here we call on questions update in my questions is not yet updated okay so we called set my questions but it should re-render the virtual Dom and it should it shouldn't have updated the state yet the correct one will be to just pass the new questions and now let's test this so let me scroll up like 151 05:08:15,420 --> 05:09:54,680 I think I did a new question okay I just roll the page click add and now let's type test one and now we have the exact same output right here and let's specify some description and look at this so both are updated and this is exactly what we want and now we'll be parent one and by the way we print the PRN state right here as well which has now the correct value so the parent object the parent component has the entire survey object which needs to be sent to the server okay and I can choose an image I can give it test title and I guess that should be updated right here that should be updated here and we can of course make it active and we can set the date and here's the date and here's the status to be active the slack is obviously auto-generated as for the description we can also give a description and it comes right here so we have the whole data prepared correctly now let me remove additional uh prints and we also need to implement the delete question so let's do this instead of model questions we're going to have my questions we filter that instead of calling set model I'm going to call set my questions and on questions update that's perfect that's perfect 152 05:09:56,040 --> 05:10:32,420 okay and now we need to test one more thing we need to test one more thing and we might need to uncomment one of those okay I'm commenting both is is not good idea but one of them if it is necessary it might be necessary okay let me show you what I mean so right now we have the following object and test questions and down below we have nested questions which nested State printed out which I am going to 153 05:10:36,000 --> 05:20:13,280 I'm going to leave it right now like this just reload the page okay so outer the entire survey and then I think I removed I haven't saved okay now we have the inner array and the outer the entire survey so I click add question and that Ed question I think comes from the Surrey questions isn't it so this one and then we have the question editor so my point is that if we Implement adding a new question from here so if I just create a dummy button and on that button click I want to call like um eight question which which doesn't exist but I'm going to create it I want to demonstrate something um here is the add question so let me actually copy these and put this in the survey View let's scroll up let's put this right here so we do have let's say we don't need the index we're going to put this at the very bottom and we have survey DOT questions right so in this survey DOT questions we are going to push new question okay let's let's comment on those two lines and we save that is this uidv4 imported not sure let's see where does this come from copy that import and then paste this right here okay and obviously we need to listen to the on click properly and call add question now we say this and have a look so we have this button let's call this Ed question and that button eight question this is the button that button is added inside the survey view Okay so in the final version we will not have that button because we're going to have only that add question button but if you want in your application to modify the questions array from this survey view component and you also want the survey questions component to have the updated questions okay so whenever I click the inner button and the new question is added that question is added right here as well okay but whenever I click that add question button and let's scroll up the new question is added right here that should be added right here as well so in this case it was actually added it was actually added because of okay it also made an HTTP request and this is something we need to first of all prevent so I'm going to give it a type of button okay let's give it type of button and then we can test this if the inner array gets updated that's perfect if not we might we need to handle this case so I'm going to click this add question and now now have a look I already clicked the dead question if we scroll up nothing happens right here as well why because we probably don't call set survey I think we have set survey don't we yes so we need to call set survey and the structure the existing survey and pass it because we added a new question inside survey questions and we need to destructure and update the actual stage so I save this again reload the page I click on this add question and let's scroll up okay this is exactly what I wanted to show to you so I clicked at question and the question was added inside the questions array okay if we scroll down below the questions component inner component didn't wasn't updated and we don't have that that question so we don't actually have a two-way data binding of these surveys of the questions array so in this case what we need to do is go in the survey questions and we can listen to the questions so right now this component gets questions right here as a prop so we can watch the change of the questions and internally internally we can call set set my questions to be questions this is what we need to do save this below the page and now let's test this I click add question and voila so we have the new question added in the parent State as well as in the child state and if this is not still clear I'm going to quickly recap what has been done right here okay so let's start from survey View and let's remove this so we have the questions model obviously and we pass down the uh survey DOT questions to the survey questions component in the survey questions component we accept the questions right here and we create internal State my questions and that my questions is something which is rendered right here iterated and rendered and we listen to question change add question or delete question and whenever one of those methods happen we update the internal State we call the set my questions method but we also call this function on questions update which is passed from parent so that the parent needs to know that the questions was updated in these survey questions component okay and these two methods set my questions on questions update is written in three places eight question question change and delete question but we also listen to the questions array and whenever questions there is updated we update the internal my questions array because for some reason if the parent survey view decided to update the questions array the child components or equations needs to have the update to one as well okay and just like this we have a two-way data binding so I click the button this is the button and which updates the internal my questions array but that also updates the parent and if I click this unstyled button which is lost this one I click on this it updates let's click multiple times it's it's a it updates the appearance State as well as the child State okay and this is exactly what we want now if we type something right here test test one two three four okay and then let's search for test one two three four we have this in multiple places first this is an appearance second this is in the child and obviously we have the third and fourth which is inside the component itself so I think this Recaps the whole thing what has been done right here so we can go ahead and simply remove these pre-tags from the survey view as well as the question survey questions component from here so I save these we load the page and everything is as is as it should be let's now test the positioning so we have test test one click add we have now test uh Test 2 and click it right here and it always creates it always adds I think at the very bottom so if I click the first ad okay now it's created after the first one and the positioning looks also really good all right now let's do one final test and create this new survey I'm going to call this test one test description let's choose like date and flag and choose some image as well obviously the images are are not relevant to the surveys and we add like three questions question one question two and question three now finally we click the save and we get a successful response obviously right now we have Dam service but if we go in the PHP my admin and have a look we should see the created survey with its questions so let's go into laravel react survey and which database do I use one or two let's have a look 154 05:20:13,860 --> 05:27:51,000 click here we use database two so click on this and now click on the surveys check the latest one which is this one we uploaded an image as well which has id5 now if we go in the survey questions we have couple of questions right here and pay attention survey 85 is three times right here so all those three questions and all of them have type text have been created okay that's perfect now let's have a look at the plane We are following we have just created this create question editor component okay we can Mark these and the next thing is to uh we need to local the user on page refresh if the token is invalid and then we can follow in the the finalize the project by Implement to display the surveys from database and and so on so let's move this on the right side and let's go and let's just reload the page okay so we reload the page and if we just change the token so let's have a look in the local storage this is our token and in local storage I'm going to call set item I'm going to pass okay to be some random string okay hit the enter now my local storage token is random and whenever I make make requests I am not authorized so if I just reload the page nothing happens nothing at all because well we don't make requests to the server side the token is available in the local storage and the react application thinks that hey we are authorized so like nothing really happens but also if we are authorized and right now it looks like we are authorized if we are authorized we need to display also the authorized users information right and we don't see the user's information if we switch to the mobile and open that we don't see that if we log out and log in then we see the name and surname or something else so I'm going to test this out as well so let's provide some credentials hit the enter now I am authorized and if we have a look in the Mobile screen we see right here my name and email and that comes whenever the that comes as a response of the login okay here's the user information if I just reload the page right now I lost that data so whenever we refresh the page I want to make requests to get that user information okay and the best place probably for this will be inside the layout inside the default layout so let's open Now default layout and let's listen to the Mount of these components and on Mount let's make requests so we will need use effect let's import that we pass an empty array and then I'm going to make request and on the backend side if we open Now API dot PHP we have an endpoint uh we probably don't have an end point but I'm sure that was available but that is available out of the box that was probably available but we we probably deleted that and let's open this out controller and we have just survey controller and out controller okay inside this out controller I want to create a new Road which will be just to return the authorized user user's information so let's create public function me and that will return let's call this correct things and we should return the authorized users information from here so that will be return request user okay and we should return the exact same type of response we return from the login so that will be just the user out user result okay so we return request user which basically is the will be the same if we go now in the API I am going to add a new road right here which will be only for for authorized users to return that's going to be me to return the currently authorized users information okay like this so we have the API ready we have the action ready if we go in the default layout I'm going to make requests using access client get the URL will be slash me and we listen to the successful response we can destructure and take all the data from here and then I'm going to call set a user or Set Set current user said current user to be data whatever is received I'm going to put debugger as well to test this so we just reload the page and we have the errors right here get method is not supported that should be get so we reload the game and here's the debugger and the data is the user information okay so we we have done everything correctly and if I just remove the debugger reload the page I should see the currently authorized user's information right here okay so I reload the page and it makes requests to the server side gets the user information and displays right here so now if I change the local storage into one two three four okay and just reload the page the me will return 401 okay and thus we listen to 401 we redirect user to the login page and just like this we will redirected to the login page and if we're having a look in the local storage I guess we don't have anything right here we don't have token and everything is good everything is as it should be okay so I think that's that's really good so we can tick that to do in this applications so that we have implemented the date part as well and the next one probably will be to implement displaying surveys from the database and then Implement pagination and update and delete and so on now let's Implement a rendering surveys from the database okay at the moment we don't make requests the only request we make is to get the current user information if we go in the surveys let's just hard code in service now let's go in the surveys component surveys.j6 and right here we need to listen to the Mount hook make request and render service so first let's use use effect 155 05:27:54,060 --> 05:31:12,622 we pass the empty array and then I'm going to make requests using axisclient dot get the URL will be survey I guess that's going to be the URL because right here we have the survey so we may get requests to the survey inside then we take out we take out data from there which should be the surveys okay but we need to actually have a look what type of data we get and I'm going to call uh well we need a state for this so at the moment we are using the state which comes from the state context and this is the place where we have the surveys we can save our surveys right here in the state context but having that data inside the Conex provider only makes sense if you want to use the same data into multiple components okay but at the moment we only need the service array inside the service component right here so we can and probably we should make it easier and I'm going to create right here a inner State not State inside the context provider but in Interstate which will be only relevant for this component it's going to be surveys and set surveys okay use State and we pass an empty array okay now we have this surveys and those surveys are actually rendered at the moment iterated and rendered normally so if we go in the browser uh by the way the request was made in here we have the data and the data contains and it's an object and it contains data internally which is an actual service array and it also has the links and meta and those are for the pagination okay this is what we're gonna use uh use the for for the pagination so at the moment I'm gonna just call set surveys in past data dot data and again data.data is an actual service array okay that's perfect and maybe we also need to show when loading indicator but let's have a look first so I just reload the page use date is now defined that was not imported here it is up okay now that was imported I saved it reload the page okay now pay attention we have service all of them have broken image and test but this is how this is what we actually created okay if we have a look in the network we're gonna also see what are the total items total is five so we have totally five surveys in the database if we go in the service table we're gonna see only five items right there okay if we go ahead and create more of course it's going to return more - but it's going to also consider the - pagination 156 05:31:13,200 --> 05:34:30,500 okay now we don't see the image but I think on one of them we have added image we just return ID slogan title we don't return image so for this we need to go in the survey resource and right here from here we need to return image as well I'm going to call this image URL and that's going to be this image basically if that exists we are going to return uh through the URL facade uh URL to passing this image okay because this image will be a relative URL this is how we implemented saving that and we need to return an absolute URL HTTP with HTTP to display that image right so this is how we are going to do next so we basically have ID title slog image URL what else do we need well probably we need status and that's going to be in this status whatever is that but the status needs to be Boolean value and that these settings will be an integer it's going to be either zero or one so I'm going to use double exclamation right here to convert this into a Boolean actual Boolean next will be to return um probably description these description and we also might need created it which will be this created it and we should format this into VR month day hour minute and second if I duplicate these uh probably two times the second one will be updated at and the third one will be expire date but we don't need our minute and second for expired date and we probably also need to return questions right because each survey contains questions and we don't plan to make a separate request to get the questions for the survey so we should return questions along with the survey information and for these we should probably use survey um well we should probably use survey question resource something like this which I think we haven't created if we go in the resources we only have a survey resource we should probably create separate resource for that so I'm going to bring up the terminal go in the first one and run PHP artisan make resource survey question a question resource survey question Source I don't want to make a typo hit the enter okay the resource has been created let's run PHP Artisan serve and we have to return an array from here 157 05:34:31,500 --> 05:36:50,420 we are going to return obviously ID this ID let's duplicate oops let's duplicate these few times we are going to return uh probably type we will also need maybe description of the question we will need probably the question text itself and the question text question should be probably above the description and the data the actual data of the question which will be like for text it really will be an empty object but for drop down or radio type questions it will probably be options so Json decode and here we have it and we have the survey questions survey question resource which should be used right here survey question resource make sure this is also imported but right now because they are in the same namespace there is no need to import that so I am going to return now a collection of these survey question resource so let's call them method collection passing this questions okay now I save this and have a look in the browser reload the page um okay we have another call to remember function first on null okay where does this happen collects okay this happens somewhere somewhere here maybe let's comment out the questions okay let's debug the problem comment out the questions okay it returns successfully it has the image as well so the problem is right here so if we go inside uh we need to have a look so we have ID type question description and Json data 158 05:36:51,260 --> 05:37:00,500 well uh the problem is obviously here so I'm gonna I'm gonna have a look at the problem once again 159 05:37:01,560 --> 05:37:11,630 okay let's find out from where does this come this comes from the survey resource line 28. 160 05:37:11,631 --> 05:41:59,360 which is this one okay that's not a news I knew that then we should have something else resources collects resources okay can't call to member function first or now okay where's the problem the problem is here and let's comment all the data Maybe the data is problem so we just roll the page now we still have the error let's comment out maybe everything I like these reload the page we still have the problem okay I think the reason for that is because we don't have relation to questions that must be the reason if I just open survey.php we don't have relation to questions so probably down below I'm going to create a function function questions which doesn't need any arguments and the return type is not also something we must declare and that's going to be this has many has many survey question survey question column class okay now if I save that and just will reload the page we don't see any error inside the data each survey has all kind of data we are returning okay everything about the question itself I'm sorry everything about the survey itself as well as the questions which is which is perfect so now we have all the surveys loaded properly okay so we have implemented now loading service from the database if I have a look in the plane uh okay we did that now we can implement the pagination which is which is really good okay let's go in the back end survey controller and I'm going to change the pagination size into into maybe two okay we need the pagination to be available now if I just reload the page it just returns two at the moment but what I'm interested is the actual response and inside data we have only two button inside metab this is something interesting so we have right now everything about the current page everything about the pagination basically in general so a heavy current page we have the from and we have also two so basically we are on the first page and we are displaying items from index one to index two we display two items per page the last page is three and total is five so we have totally five items and we also have links and at the moment we have five links and the first one is basically disabled active false and the this one is the first page this one is the second page this is the third page and this is the uh next page basically and it jumps into the second page okay so if we want to implement the pagination it is as easy as just iterating over the links and rendering them properly so as a template initial template for the pagination I am going to use this Tailwind components Tailwind components where's that Tailwind UI here we have it let's scroll down below and here is the pagination click on that and we have this example pagination and I won't react so let's click on code this is the react example component and this is our links okay um do I need everything probably not but we have to copy everything and then modify that let me copy the HTML only I don't need anything else 161 05:42:01,320 --> 05:42:45,680 okay I don't need anything else and I'm going to create a separate component for that let's go under under react folder Source components and create new component call pagination pagination links Dot jsx okay let's well let's paste copy everything everything and paste now the component is called a legend we called pagination links 162 05:42:46,080 --> 05:43:02,840 okay and that copy the hero icons links as well which is perfect and let me actually use that component right now in the surveys js6 163 05:43:04,260 --> 05:48:14,780 by the way I also want to display the loading indicator but let's put this right here ignition links that must be imported make sure that the import is written in your import section so I saved it and have a look and have next and previous and if I increase the screen size this is the pagination links component okay okay that's that's fine that's perfect I like that um it has the summary as well and has the buttons okay before we finalize the pagination let's create right here a loading indicator so right now if I just reload the page I don't see anything and if the network is slow well you have to just wait and the screen looks like Frozen so I'm going to duplicate these I'm going to call this loading and then this will be set loading and the use state by default loading will be false and then let's remove this console statement and then right here I'm going to call set loading and that set loading will become false but before making requests I'm going to - call set loading to be true okay and - then down below um probably right right here uh maybe even the pagination links should be wrapped inside so I should probably create an additional div which includes which will include the pagination links as well like this and then additional D which will be just for loading okay so I'm right now just writing a text loading but in real applications you should probably show a spinner so this loading will only display if the loading is true just like this okay and the second div will only be displayed if the loading is false just like this so I save that and now pay attention loading and then the items appear loading and item appears okay well you should probably put this in the center text Center and probably change the font LG or text LG to increase just its size nothing else okay perfect okay now let's get back to the pagination part so let's go in the pagination links and this one has a bunch of talent scissors classes I'm going to add one more which will be Shadow LG save it and we have this Shadow and margin top maybe four as well okay this is our pagination and probably we should change the shadow into Shadow MD okay like so now these pagination links component should accept a couple of props so it should accept probably the entire meta object coming from the server okay here we have these meta which contains the links and from into everything and then it will render this part and this part as well so we should accept meta right here and then now let's Implement rendering so we have the we have something which is only visible for small screens like previews and next buttons okay and this is hidden this is hidden above small screen okay let's collapse that then we have showing this is from okay showing uh one to something and we need to use meta from a metab2 so right here we will need meta from two right here we need meter two okay off and then we have the 97 which will be meta dot total we have I think total as well so if I just reload the page uh we have obviously error because we don't pass me down if we go in the survey jsx right here we're going to pass Nita to be something and we don't also take out data.meta and save it so we have to create one additional state which will be meta 164 05:48:15,480 --> 05:48:36,600 and set meter and that should be object then right here I'm going to call set meter passing data dot meter save that and then we pass meta 165 05:48:37,080 --> 05:51:20,280 now let's see showing one to two of Five results this of Five results needs to have um some kind of space like in bsp or something like this okay one two two of Five results okay this left part is already correct now let's take here about the right part in the right part we have these previous button which basically at the moment jumps at the top or which should be disabled okay well let's do like this so we display previews then we have one two three and so on and you know what I'm gonna do I am going to remove all those links not next but 10 9 8 this as well all of them and to let's live two and we have one so we have only one and two now I'm going to iterate over one and two and based on whether the current link is active or not I'm going to add additional classes okay this is for active this is for normal and again having a look at the meta links we will identify active flag so the first one is actually active active true and the other has active false so now right here we need to iterate and it's going to be meta dot links dot map link and we're in a map into into the following type of anchor link however these color classes like border Indigo 500 or text Indigo 600 is something which should be added conditionally if the link is active however before that let's output the actual link label we have labels right here so here instead of one hard-coded one we should have link dot label all right so let me comment out this part save and have a look so now all of the links are actually active 166 05:51:24,840 --> 05:51:29,600 okay I think that makes sense we have the left one 167 05:51:29,878 --> 05:52:17,480 okay we have the right one okay that makes sense that makes sense that those all of them are displayed so we probably need to remove this uh previous part as well and we have to make basically do a small adjustments so pay attention that this one has rounded left MD okay so we need to add this class if the link is the first one and the first one can be identified using by index so we have IND right here so now let's add uh some classes so we can change these into this way 168 05:52:19,378 --> 05:53:27,680 like like these so we have all those classes already added and we have to add additional classes plus if the index equals zero let's put space extra space right here if the index equals zero we add class rounded lmd to round the left side like this otherwise let's put space otherwise we don't add anything okay now I save that and have a look now if I zoom in oops that's too much here we go so this link has the left sides round if you can if you can see that okay so this is this is exactly what we expect next we are going to add an additional classes let's duplicate this if the link is active so link DOT active if that equals true we are going to add these classes border 169 05:53:28,620 --> 05:53:45,740 we are going to add text Indigo as well like this okay otherwise we don't add anything or we add default Styles which will be border gray 300 170 05:53:47,820 --> 05:53:55,499 here and text Gray probably 500. 171 05:53:55,500 --> 05:53:59,958 like this so I saved it 172 05:54:00,540 --> 05:54:06,620 I think this is not what what I wanted 173 05:54:07,260 --> 05:54:11,180 if I just uncomment this 174 05:54:13,920 --> 05:54:19,878 two okay this is this is what I want 175 05:54:21,298 --> 05:54:35,360 PG Indico 50 this is also something which should be added if the link is active saved it okay that's more like it 176 05:54:35,820 --> 05:54:48,020 but it's more like it and we need also hover effects here we have this hover which should be added 177 05:54:52,260 --> 05:55:16,400 to have hover effect for this one no we don't have so we put this right here save that we have horror effects for each of them and that looks nice however now we need to remove this part we need to remove also next 178 05:55:18,360 --> 05:55:24,558 we have to do this and previous 179 05:55:27,180 --> 05:55:30,378 so I saved it 180 05:55:30,920 --> 05:55:36,058 and we have broken something 181 05:55:37,980 --> 05:55:42,200 this is different this is different 182 05:55:43,080 --> 05:55:47,780 okay this is something which should be removed as well 183 05:55:48,138 --> 05:56:03,320 okay that's perfect so we have the pagination implemented the first link this one should be rounded but it is not rounded 184 05:56:09,660 --> 05:57:13,700 flat space okay now this is rounded that should be rounded as well so we are going to add rounded right AMD if the index equals meta dot links length minus one okay so we're going to round the right side as well and now if we want to render this uh HTML entities properly we have to display the link.label as an HTML unsafe uh something okay so for this we're going to search for react uh render HTML unsafely something like this dangerously set in your HTML okay this is what we need this is what we need where's that 185 05:57:15,780 --> 05:57:36,378 we have this HTML and we have to set the tag dangerously set in your HTML which should return HTML okay so if I just give this attribute to this a okay like this 186 05:57:38,100 --> 05:58:02,480 and then and then we're going to pass right here an object so that should be an object underscore HTML corresponds to link dot label label too many colors of braces remove this and have a look 187 05:58:02,820 --> 05:58:17,480 dangerously situation must be form of HTML I think this is what I return uh double underscore yes 188 05:58:18,718 --> 05:58:23,420 can't read properties of final find reading map 189 05:58:23,700 --> 05:58:29,420 okay it looks like something is wrong 190 05:58:30,120 --> 06:00:51,558 if we just reload the page the request is not made okay and it looks like meta links is is not available and then we call map on that which is not relevant so maybe we should put an additional check if meta links exist then we start iterating over that okay now let's see okay so that's good we have the links okay we have hover effects we have we have everything what we expect to have and this dangerously set inner HTML also works as it should work the only thing remaining here is whenever we click on the buttons it should actually make requests or shouldn't do anything if it's uh if we are clicking the previous button okay so we have a hashtag right here I'm going to remove that and whenever I click this previews it should not do anything because there is no previous actual link so we can put an href but we need on click right here on pagination or let's just call this one click because we are inside a small components and we can just call this on click function on click uh we can accept an event right here and then we're going to call event three event default and we need to check well we probably need an index of pagination as well so we have an event and we need index as well well it's past the let's accept an event rate here then we're going to call on click pass event and index so right here I'm going to check if the index equals if the index on which I am actually clicking right now or maybe or maybe oh wait hold on 191 06:00:51,840 --> 06:02:25,878 so if we have a look in the preview maybe in the network Amita links okay URL if the URL is now we don't need to do anything this is the rule so we check if we should accept a link instead of index we should accept the link if link dot URL does not exist then we simply return and don't do anything if that exists we should aim it peering that this particular particular URL has been clicked so we should probably accept right here on page change or something like this and then we're going to call on page change uh passing link or maybe on page click okay and let's find this on click and win to pass link instead of index so right here we need to pass link I think that's looking really good if we go now in the surveys we need on page click let's create that function right here as well on page clique let's scroll up create right here const on page click 192 06:02:28,680 --> 06:03:01,218 we are going to accept uh link and then we need to make a request to the link.url to actually get uh the surveys okay and I'm going to take out this part now and create an additional function const get surveys Arrow function and we accept the URL right here and then I'm going to check 193 06:03:01,740 --> 06:03:38,958 I'm going to check if well let's do like this URL equals URL or slash surveys survey basically if we don't pass the URL we're gonna take out the survey and make requests to that now I need to call these get surveys unmounted get surveys this set loading should be part of this get service so we get the URL we set loading yeah yeah 194 06:03:41,520 --> 06:03:45,020 and then right here 195 06:03:45,360 --> 06:03:48,860 get surveys 196 06:03:49,740 --> 06:05:33,680 and we pass link.url so I saved it okay now everything looks good and this next and previous is something which we also need to handle okay but let's enlarge this and click on the two the request is made and second two items are rendered showing three to four of Five results click on three and one item is rendered showing five to five or five results clicking next doesn't really do anything clicking previews works exactly as it should work okay and now it doesn't do anything as well okay additionally as a small challenge to you you can add extra CSS classes to those links right here if the link URL is empty so you can make this more like looking disabled okay and small small challenge as well so right here the right border is missing so find out this on your own and make this working okay small scissors challenge but I think it's gonna teach you something okay we have the pagination I think ready and having a look at the plan so we have implemented pagination did any same thing I have feeling that I missed anything right here um 197 06:05:34,558 --> 06:06:03,440 have the pagination next previous yeah everything looks looks really good but sure if I have missing anything yeah I know what I missed I missed these links okay I think these links doesn't do anything at the moment because they are just for the mobile okay 198 06:06:03,718 --> 06:07:08,240 and now let's have a look in the survey and we have links and we have meta okay now I think what we need to do instead of taking meta and by the way we can take out meta as well and we know that the first link will always be previous in the last link will always be next maybe we can take out this as well or we can take out from links first and at first probably previous and next but this links is something we don't use we use meta all the time and we also pass meta right here as a prop so from meta links we should take the first and last so here we have these links which is only available for the mobile and let's give it on click on the function called on click 199 06:07:08,600 --> 06:08:18,980 let's accept an event and we pass event and I want to pass the first one or maybe not the first one okay hold on maybe not the first one but the previous one right and the first one is always the previous okay this is the thing so from linksmeta dot links I am going to take the first one okay and pass it as a link right here and let's copy this on click and give it to the next one and this is going to be the last one so So Meta dot links length minus one let's save it and have a look so previews doesn't do anything next opens the next page next on the one item and next doesn't do anything okay so we have successfully implemented pagination for Mobile screen as well perfect 200 06:08:19,320 --> 06:09:11,900 okay having a look at our plan again so we have implemented showing loading indicator on survey open um well no no this is something else uh we show the loading indicator when opening the list of the surveys but whenever we go inside the survey each survey like click on edit right here that should open the survey in your page and then we should see a loading indicator and by the way I think the link is broken so we should open survey list item where's the edit button we should probably put slash right here let's go back and click on edit service five okay something is wrong let's open now router 201 06:09:12,660 --> 06:10:14,298 okay we don't have an edit road for the survey so this is something we should Implement right now search surveys we have create and we should Implement edit as well okay this should be the surveys edit but we should take out the query parameter from the URL make request to the server get the survey information load it into the form and then handle the actual update so now let's go in the survey view right here and I am going to use hook use params and I'm going to take out ID from there so use params our arms like these we have the ID now I need to listen to the Mount hook and check if the ID is available so use effect 202 06:10:18,958 --> 06:10:32,780 if if ID is available then I'm going to make a get request to get the survey information so using axios client dot get 203 06:10:33,120 --> 06:10:36,620 uh surveys 204 06:10:38,280 --> 06:11:28,580 like this and passing an ID inside then we get the actual let's destructure that take out the data and let's put debugger and we have a survey model already defined right here okay so and if we don't make get requests if the ID isn't available then the survey is a new survey new object okay however if the request is made and if the data returned we call set survey obviously and we assign data to that and that's going to be how many arrows do I have here I think too much right 205 06:11:29,760 --> 06:12:50,000 yeah um and that's going to be the survey loaded into the form okay so let's open the developer tools console maybe as well and have a look so when we make requests we get not found because I think right here we need a singular form survey ID let's just reload the page okay and we got the response and that data contains another data inside and there okay and we can set this data.data here and remove the debugger so we reload the page and now the form the survey was loaded into the form and we have the image and title and description and dates and we even have questions loaded properly okay so this is this is amazing the title needs to be changed instead of creating a survey it should be update survey where is the title right here okay let's bind this title like this and that should be 206 06:12:50,520 --> 06:13:31,760 or update survey okay and if ID is available if ID is not available then we have create new survey otherwise it's going to be update survey so in this case it is update sorry if I just reload the page update sorry if I just try to access surveys slash create that's going to be create new survey okay let's again access to the fifth one we have update survey and we need to display the loading indicator as well so let's let me make sure to copy this part 207 06:13:33,240 --> 06:14:28,378 and the default value for the loading should be false we have loading here and set loading now this loading set loading true set loading pulse and then we have form probably the entire form should only be displayed if loading is false like this if the loading is true then let's create div element with the loading text and just like we did or the surveys.jsx 208 06:14:31,620 --> 06:15:14,840 this part maybe we can copy in this right here so I saved it and reload the page and loading and then the form appears okay I think this is amazing this is fantastic and now let's handle the update so whenever we click on submit at the moment we prepare the data and we make post requests okay and then of course we navigate user to the surveys page and we also catch the errors but we need to do something very similar if if the ID is available but we need to make a instead of instead of post we need to make put requests so 209 06:15:15,958 --> 06:15:27,558 let res equals null Maybe if ID is available then axios client dot put 210 06:15:28,160 --> 06:15:43,400 axisclient.pot we are going to ask the URL to be survey slash and ID we need to pass payload 211 06:15:43,680 --> 06:15:49,218 oops if the ID is not available 212 06:15:59,100 --> 06:16:01,700 foreign 213 06:16:04,820 --> 06:16:35,362 and then the rest of the things are the same okay now let's have a look we have update and we it should make put requests right now if we go in the network we have an error what's that okay reload the page okay we have in our value prop context area should not be null consider using an empty string to clear the component - okay that is a very very descriptive - error 214 06:16:36,718 --> 06:18:38,120 okay should not be null value prop on texturity should not be now okay scroll down below we have title and description and this is text area why the survey description is null it is an empty string well I think the error is not coming from the text area of the survey description but it's coming from the question description from here so if we go in the network and just open and have a look in the questions I guess the description is coming now and that is causing the problem if we're going to question editor we have a question type and the description and right here we can pass the value or an empty string if you save that and reload the page the error basically disappears and this is what we we are looking for let me remove this pre comment out okay and everything looks good and we need to test making a put request so I'm going to just change the survey title and call these updated and hit the save and we have validation errors expiry date must be day must be a date after today so this is this is exactly today so I'm going to make this into a set into 10 so hit and in the update worked okay let's now test the lorem ipsum something in the description click on Save uh we have another expired date okay what's going on I guess the expiry date was not updated if I set this into 10 and make request 215 06:18:38,638 --> 06:19:02,400 inside the expired date we have now obtained but if I edit that it's still eight so we should check this on the backhand side survey controller we need to look for um we need to look for update 216 06:19:03,420 --> 06:19:08,298 or maybe check update survey request 217 06:19:09,360 --> 06:19:31,820 we should have expired a to nullable date after today and what is the data or maybe just return entire data from here let's click on Save 218 06:19:34,440 --> 06:19:38,840 okay let's set this into 10. 219 06:19:40,020 --> 06:19:42,798 click save 220 06:19:47,820 --> 06:20:10,218 okay what happened so we make with request and we immediately return the whole data and this is the data we passed including expired date but the expert date was not changed why if we just go in the survey PHP 221 06:20:11,580 --> 06:20:15,980 we have expired date rate here in the fillable 222 06:20:16,320 --> 06:20:20,600 why doesn't the Explorer Date Update 223 06:20:21,298 --> 06:20:26,420 we call update passing the whole data 224 06:20:31,620 --> 06:20:40,820 let's click on edit maybe it is actually updated but we don't populate it correctly 225 06:20:43,040 --> 06:21:47,240 no it does not update I checked in the database and found out that the actual export date is updating okay so we make requests properly it updates if I just reload the page and then click on the edit which loads the inner content then we have the explore date 8. so I guess I guess we have something wrong in the survey resource if I just open survey resource uh basically in every place this is sometimes I feel stupid okay so in every place we return created it but we should have return expired date all right so I just reload the page and now we have another and there tells me that the format on string call to member function format on string 226 06:21:51,180 --> 06:21:59,958 okay probably this expired date is string so we have to convert this into date time 227 06:22:01,558 --> 06:22:10,458 like this and then we can call ormat on that 228 06:22:13,558 --> 06:26:52,760 okay and here it is correct now let's test updating the questions let's put additional symbols right there that was updated click on edit here's the question here's a question okay so everything looks good so we have updated let's update the image as well and choose something else and click on Save and the image was also updated okay we have actually implemented updating the survey and we have the loading indicator when we open the server in your page as well now let's Implement deleting survey at the moment when we click on the delete button nothing really happens let's open vs code and I'm going to open survey item survey list item and right here we have this button and we listen on delete click okay let's have a look in this on delete function which comes from the survey list let's open survey I think it's called surveys.jsx and right here we have this on delete click and at the moment we just click a console log so from here we're going to make we're going to use access client and make delete request on the following URL so that's going to be survey and we're going to pass right here survey ID but we don't get actually which survey we want to delete so if we go in the survey list item from here from down below we have the survey ID so we are going to apostate survey ID survey dot ID right here in this function and then we accept ID right here okay and then we can pass this ID right here optionally we can add a confirmation let's create window confirm we know confirm are you sure you want to delete this survey let's do like this and if the user accepts that then we're gonna delete the survey and we'll listen to successful response we get an actual response but we can destructure take out data but we actually don't care data coming from the as a response of the following endpoint so in this case we are going to just redirect user to the surveys page just like we do when the survey is created so we are going to use router dot navigate and redirect to service okay so let's test this let's open the console we have an error each child in the list should have a unique key problem that's accurate and correct so right here uh we actually have this so this comes from the pagination links I see so if we open pagination links we have right here we are using a map right here so on this item let's specify e to be which to be the key it should probably be link dot URL because that's going to be the unique and whenever we click on this we use link.url to navigate to that page so link.url will be unique one so let's just reload the page and there are still errors encounter two children with the same key okay I see that also happens because we have the previous link as well as the first one so if we scroll down below the next one has link the URL to which has the page id2 but this one also has a link with page id2 so in this case The Simple Solution will be to use index okay let's go with the index now let's reload the page have a look no errors now I'm going to click delete on this broken image one a confirmation pops up click ok and nothing happened let's go in the network we actually see that the request was made and if I just reload the page 229 06:26:54,480 --> 06:30:40,940 okay it was not deleted it looks like it was not deleted okay now we have no it it actually was deleted because we had five items now we have four and if I just reload the page now we have three okay that is actually deleted but but when we just click delete we still have three right here because because I didn't do it correctly instead of navigating to service we are actually on the surveys page we just need to uh call getsurveys again so I'm going to call get surveys like this okay so let's have a look now we have two items and I'm gonna click on delete here click ok and now we have just one item I think that's good so we have now one item and delete actually works what else do we need to do we can actually hide the pagination parts if the if there are two small amount of surveys right here we don't need this pagination links and let's by the way do this but we don't know actually how many items is um for each page so let's assume that we have 10 items 10 surveys for each page in this case if we go right here we have this nav and we can hide this now completely if the total is less than 10 okay so let's do this let's wrap this and curl the braces and if Mita dot total is less than well actually if it's more than or equal and 10 and then we display this now okay otherwise we just don't display and now we don't have these links right here okay so there's just small improvements maybe you don't want that Improvement and you always want the pagination links to be displayed even if there is only one page so you can just leave that okay next I'm going to do is whenever I click the edit um well actually let's have a look in my plane so next is what I want to do is that whenever I click um on each survey we should show a loading indicator but we do actually have that okay so if I just reload we see loading and then it appears so I'm going to mark this as done and this is also done now we need to show notification on survey create update or delete let's start working on the notification when the survey is created updated or deleted for this I'm going to create state in the context provider let's open the context provider and right here I'm going to Define state for that notification and let's call this notification toast and it's going to be an object it will have message and it will have show property which by default will be false so now I'm going to go in the layout default layout and right here somewhere in this layout I am going to include that I'm going to include the toast notification component okay but we don't have that component created yet so I'm going to go in the component section components folder and create toast.jsx okay let's generate the component let's remove this 230 06:30:41,600 --> 06:31:39,539 okay let's remove this um and let's give each tolerances classes it's going to have a padding Y2 paninix three let's give it um text white rounded and BG Emerald um 500 okay and let's put some lorem ipsum text right here not that much perfect so we have a component let's go in the default layout and I'm going to include that component somewhere right here it's going to be toast fine make sure that the component is included somewhere right here I'm going to also give this components position fixed and let's give it also left to be 2 and bottom to be 2. 231 06:31:39,540 --> 06:31:51,839 so and let's give it ourselves the index say um let's give it Z 100 maybe or Z 50. 232 06:31:51,840 --> 06:32:09,680 okay all right so I have it saved and the component is available right here okay as you see we can actually increase the left and bottom a little bit maybe we can put this on the right side if you want so 233 06:32:10,200 --> 06:36:33,860 that's correct so just like this but these should be only displayed if the sum value inside the context provider is set so if if we set this show into true only in this case the toast component should be displayed right now it should not be displayed so right here I'm going to Define I'm going to use these State context okay const State equals use state context like this and then state has toast and show and do you know why excuse me so actually the state does not have the toast because we just added in the default value but we have not exposed the toast in the context provider right here okay so right here we need to expose this but before we expose we need to create that create that state so let's define const um toast and set toast equals use state okay in the default value will be message is empty string and show equals false and now we expose toast and set toast like this now I'm going to go in the toast component and the structure that state and take out toast and set toast now I can take this toast and conditionally display if toes dot show is true then we display the component just like this all right so let's see what's going on here let's wrap this inside a fragment like this okay so I save this and we don't see toast now I'm going to go in the context provider and change the default value for the toast to be true so make sure you change the default value from here inside the context provider inside the user State not inside the default value right here because this is only for auto completion purposes so I want to set this into true save that and now we see this message right here okay and that's perfect let's set into the false and I'm going to also go right here and instead of lorem ipsum I am going to Output toast Dot message all right perfect now let's go in the surveys um and whenever we deal with a survey I am going to show the toast message okay before I call get surveys or after after I call get surveys I'm going to call this set toes for this I will need to use the state context okay equals use State context like this I'm going to destructure and take out set toast method and then I'm going to call said toast said toast accepts a message accepts a message it's actually accepts an object which has message in the show but I'm going to create a simplified version for that so let's actually try this before I do a simplified version message equals test and show equals true okay so whenever I delete a survey let's have a looks here is test okay that is actually displayed okay so far so good uh by the way let's display right here you don't have any survey items now let's scroll down below and we have loading and if it's not loading then we have a grid and then iterate over our surveys okay so before I iterate I'm going to do like this if surveys length equals zero I'm going to create div right here 234 06:36:34,260 --> 06:37:54,440 like this you don't have surveys created perfect let's give this one I'm adding y um maybe eight okay and text Center and text Gray 700 let's try like this you don't have surveys created okay this is not in the center because we Define this inside discrete we should create that outside of this thief right here let's save it and now that's that's more like do you have service created and we have resignation links which by the way should not also be defined so let's add this additional check right here if the service length is more than more than zero only in this case we display the pagination links and now we have we don't have service created we have this test always displayed right here and why do we have that because I put this say toast well I don't know why it's always displayed 235 06:37:57,298 --> 06:39:28,280 this test okay it's not displayed it's not displayed okay now let's create new survey and display the notification but I just want to pass a message I don't want to pass the message as well as the show property so instead of say toast I'm going to create in the context provider show toast message function const show toast equals we accept a message right here and then I'm going to call said toast which will accept an object and we pass message and set show to be true okay just like this and I'm going to expose these show toast I don't want to expose say toast I'm going to remove that and only expose show toast now if I go in the toast I can actually delete this set tool so we don't need this however in the surveys I'm going to take out the show toes and I'm going to call show toast and only pass message okay and the message will be um the survey was deleted in this case now I'm going to copy that and go in the survey survey view page and let's search for um submit submit okay where is the submit function 236 06:39:29,638 --> 06:43:38,900 on submit here it is okay and whenever we make requests inside then after we navigate in surveys I'm going to call this show toast and show toast needs to be defined so I'm going to copy this line and put this at the very bottom of my at the very top of my component okay now let's go in the surveys click create use context okay we have to import that here it is imported save that okay perfect so test survey test description let's make it active choose the date and maybe choose the image okay click on Save okay we have an error what's there the expiry date must be date after okay we need to choose this in the future click on Save okay the survey was the um I'm sorry I'm sorry it was it wasn't deleted it was just created so let's search for deleted keyword survey was created I don't like that the survey the message basically is sometimes very small sometimes very large I prefer it to be fixed width so I'm going to go in the toast and give this one fixed width W and square brackets I'm going to find like 300 pixels let's save that and now we have it fixed width okay and if there is too much text ends goes on the second line now let's create second survey test let's click save okay the survey was created that's perfect now we have this test right here however I I want this notification to be automatically hidden after five seconds so I'm going to go in the context provider and right here when I Define the Seto when I call that set tools and create and show I'm going to create set timeout and basically after 5000 milliseconds I'm going to call set toast with message to be an empty string and show to be false okay now let's test this I'm going to click create test to click on save that was created survey was created is displayed let's wait for a few seconds and then the notification is Now hidden okay that's perfect now let's Implement displaying the notification when survey is actually updated but I think it's already implemented out of the box because we create and update then is written in a single place but we always display let's wait now we have an error expert date must be date after today again let's change this click on Save the survey was created okay this is something wrong if we go in the survey view so right here we check if the ID exists we make put requests if it doesn't exist we make post request and down below we have this event and this basically is then for both of them so right here we need to check if ID exists then we need to display survey was updated else we need to display survey was created let me change this into updated and then we have created but I think we have some kind of bug I'm going to click and edit the date is correct where is the back let's check the back okay here it took the 11th did I create this with 11th date mature 237 06:43:41,400 --> 06:43:44,819 okay let's just reload the page it's 11. 238 06:43:44,820 --> 06:44:04,280 if I click save I get an error that the expired date must be date after today I'm going to change this into 18 click on Save and the survey was updated okay that is correct however I'm going to check what is the date 239 06:44:04,620 --> 06:44:31,700 it's always now 18. let's check the Where's the pagination by the way aha so we set the pagination to be uh we set the pagination to be 10 but actually that was not correct so we get the meter and then we have where's per page per page okay we have this per page and we have total foreign 240 06:44:37,680 --> 06:44:46,160 scroll down below and if the survey is length is 241 06:44:46,440 --> 06:46:06,200 more than zero then we display the pagination links that's correct if we go inside the pagination links now here's the problem so if the meta total is more than meta per h per underscore page only in this case we display the navigation okay and just like this we have it okay and this is this is cool and if I delete one item then the survey was deleted notification is displayed and we still have this notification well maybe we should remove this equal if the total is more than per page only in this case we displayed this uh paginational links but and now it's simply disappears if we add equal sign rate here then it appears okay so I think everything looks good so we have notification when the survey is deleted created updated this is exactly what we uh we should have done just one additional thing I want to add animation to the notification so if we go in the toast I want to animate this whenever this is displayed 242 06:46:06,660 --> 06:50:09,840 yeah so first of all I'm going to open the white another divide by Talent config I think I don't have talent config so do I have that yeah I do have that Talent coffee and right here I'm gonna add the animation styles I'm going to quickly copy and paste that those animation Styles and we need two things we need keyframes and animation so inside the keyframes we Define fading down which is the name from this position it should animate to this position okay from transform translates basically I move this a little bit up and then opacity is zero and then it goes to the following position transform goes into zero and the opacity goes into one and the animation itself is fading down fading down 0.2 second easy in out both okay so I need to now add this class into toast so let's edit right here animate paid in town I saved it now I'm going to go right here and let's just delete one survey and look at this I think that was really nice animation okay and let's create new survey again test now let's choose the date or maybe we don't aha this is so if you if we just leave the expiry date empty it's going to take today Okay click on Save the survey was created okay perfect and if I just right click edit here then it has today that was the that was the thing I was trying to figure out okay now let's create new survey and remember when I said that we had different types right here but we have only implemented text and I gave you a challenge to implement select and Radio and checkbox on your own so you probably remember that if you have not implemented that this is the time where I'm going to implement it okay if you want out right now spend some time you might need to spend several hours maybe one day to implement the functionality but try it to implement on your own okay this is where you learn most this is where you learn more than just watching the entire tutorial you learn you will learn how to struggle and how to make some achievements on your own without any kind of tutorials or things like that let's create now a test survey test survey I'm not going to give a description let's give it date in the future I'm going to make it active and let's define a few types of questions okay let's give it this is text type of question I'm going to add one more that's going to be select select I'm going to add one more that's going to be radio and let's save it and if I click edit right now I have all the all three questions but the types actually why do I have by the way four questions the sa4 mature one two three four okay let's hit save again and click edit one two three four okay I don't like box I'm going to figure this out did I mistakenly clicked one two three 243 06:50:10,558 --> 06:51:40,798 well-wing to give it like question one question two and question three let's hit save and click edit one two three okay maybe I didn't I clicked one extra button and for that um I simply saw there four questions but let's start implementing the select or drop down because they are going to be very very similar okay so the first one is text the second one I'm gonna switch this into select and when this is Select - we are going to display right here - options now let's open survey question or question editor where is question editor I think that's the place and now let's have a look so this is the question editor we have description we have the question type okay here's the question type and whenever the question type is Select or radio we have to display some kind of options so let's create a div right here and I'm going to display the Steve only if the question type modal type model DOT type if that equals select 244 06:51:41,160 --> 06:54:21,680 okay and I'm gonna also print model DOT type right here okay let's format the code and have a look here is Select here is text so this is the type here is text as well if this is Select now I'm going to display an input fields which will be options as I mentioned so right here let's let's create just a one option with an extra button to add more options so we I'm going to display well we need let's display the entire model we need to have option to possibility to add as many options as as user wants okay so we have to json.stringify this and let's see this is entire question and inside the data which is by the way an array we can have options okay first I'm going to move this below description I think that's going to be more logical and then we have this modal.data which let's have a look so which is an array I'm going to assume that this will be an object and I'm going to convert this into an object if it is not and inside there we're going to have options okay so now let's define right here an extra div one div which will be a wrapper for basically everything let's let's leave this model by the way so let's have a div wrapper for everything and then I'm going to have another div that's going to be for yeah for the options okay so and that will have a check so we're going to check if that particular type of question needs options so I'm going to create a function which does not exist yet I'm going to call this should have options okay and if this specific type of question should have options and then I'm going to display that div which will be basically container for the options okay and let's format everything so inside the div I'm going to have a title which will have it like an options text right there and inside let's give it classes like text small and font semi bold and let me copy and paste few classes 245 06:54:22,680 --> 06:55:13,820 okay so margin bottom and then I'm gonna put a button right there I'm going to copy it paste the button classes as well so that's going to be normal button we'll type button like this and that will have the following classes okay and let's give it text Aid okay now let's create these should have options so that basically should return true or false function should have options and we're going to return true if the question type is either select or radial or checkbox 246 06:55:14,100 --> 06:59:30,260 if that includes modal.type then we this will return true okay so I'm going to save this and now let's have a look so all of them are texts I'm going to change this into select and now as we see options appears and the 8 button is right here as well okay now we can display we can display first option so whenever we change the type into into a question type which should have options we should also add a single option inside the options array so let's scroll down below and whenever this happens whenever this happens so I should probably create a function on type on type change and let's scroll up and create function on type change we accept an event then we do what we we're doing basically set model with events Target value basically everything is as it was before but inside the model dot data so I'm going to basically change first of all I'm going to check which is the type so the type was changed and if should have options basically I'm going to do it like this if I can call should have options but the point is that at that moment I just called set model okay and the model type might not be one of these okay will not be one of these so I'm going to do in a different way and this should have options we'll accept a type okay and which by default will be now and type equals type or modal type and then I'm going to use type right here so basically you should have option will work in the same way as it was working before if I don't give type okay if I don't give type it takes modal.type but if I give type it assumes it takes the following type so in this case I'm going to call if should have options but in this case even Target value which is the new type okay if the new type should have options then I am going to do the following model dot data model.data should be an object basically I need to put this inside the model so I should move this down okay I'm going to create a new object new model let's call it like this and we have the following values inside and then I'm going to pass new model right here but inside new model I'm going to chain few things new model data will be an object and we're going to have options right there options will be an array and we are going to have one option and we're going to have the option will have uuid which will be uu ID I think we use this euid V4 V4 somewhere in the survey view yes so I'm going to import that get the very very top uu ADV for let's scroll down below E4 so this creates the uid and we can have also text right here which will be an empty string okay so each option has ID and text okay now let's save this and have a look we have options this is actually select let's reload the page 247 06:59:31,860 --> 06:59:53,160 now let's change this into select and now look at these options data is now object and it has options and now let's start iterating our options okay let's scroll down below and right here below this H4 248 06:59:55,138 --> 07:00:17,600 maybe right here okay I'm going to create one div a witch let's put right there a text you don't have options defined okay and let's give it also some Talent CSS classes like this 249 07:00:18,780 --> 07:00:33,298 and that will be only displayed if model data options length length equals zero 250 07:00:33,718 --> 07:01:07,520 okay and we're going to have else case if the modal data options length is more than zero and right here we're going to iterate so we have modal data options map we have each individual option here and we return a div from here 251 07:01:09,138 --> 07:01:19,520 and let's take also index and I'm going to Output the index 252 07:01:19,798 --> 07:02:43,280 index plus 1 first let's wrap this inside span and let's create input which will be which will be option text basically okay so let's give this value to be option dot text and we need two-way data binding so we're going to listen to its change as well on change we take event and then I'm going to update the actual option so this is something we need to take here a little bit later let's let's leave it as it is right now and I'm going to have also a button which will be a delete button so we need a trash icon for that and we have the trash icon inside survey list item here's the trash icon let's put this make sure that the trash icon is imported at the top here it is perfect and the button will probably need some tolerances classes so I'm going to give it to make it nicer like this oops 253 07:02:45,478 --> 07:02:58,040 and and I want to have a look so option is not defined it should be op dot text 254 07:02:58,378 --> 07:03:50,240 let's let's delete actually and leave only one question select okay so here are the here's the markup basically but we need to add some CSS classes so first the this D we're going to give it Flex items Center and margin button one this pan will have let's give it w 6 fixed width and text small let's put also dot right here and for the input let's give it it will need a little bit more classes so I'm going to copy the classes for the input 255 07:03:50,820 --> 07:04:06,620 like this so we saved it now let's have a look okay that's more like it and let's let's give the button also 256 07:04:07,500 --> 07:04:15,359 let's give it also text red like um 500. 257 07:04:15,360 --> 07:04:21,500 and I want to also reduce its width and height 258 07:04:21,780 --> 07:04:41,840 okay I think that's better so we have no options here and whenever whenever we click this add button it should create new options so let's scroll up here's the button let's Listen to It's on click 259 07:04:42,240 --> 07:04:59,240 add option okay now let's scroll up and create that function add option and we're going to call set model 260 07:04:59,580 --> 07:05:32,718 do we need to actually call set model data options push let's have a look uuid is uuidv4 and text is an empty string okay now let's let's actually delete and leave only one and save it 261 07:05:33,600 --> 07:06:32,958 and now I change this into select and click add okay nothing happens that's because we haven't updated the Dom was not updated because we didn't call set mode so I'm going to call said model and pass the structured model now we have five options actually already added so now I reload the page and change this into select and click add and it is edit click add a few more times and we have more options available right here okay I want to type something like option okay typing doesn't really do anything because the value of each option we don't have two-way data binding and that's the reason so the value where is that 262 07:06:33,780 --> 07:06:41,660 I think this is it so the value is option text okay and it is always option text 263 07:06:42,660 --> 07:06:57,558 okay if I just delete this option text then typing inside the input works fine so what I want to do is give it a value option text and I want to listen on input 264 07:07:00,000 --> 07:09:32,840 or maybe maybe on change and we get event and we have event Target value so option dot text equals event Target value but this will not change the model so we have entire model right here and if I type something it really doesn't affect because the model is not changed we have to call set model so I'm going to create curly braces right here and create call set model and pass entire model okay I should mention that this is not the most efficient way to implement this because every time we type something in the option the entire model is Rewritten Okay so this is not the most efficient way to implement this and now let's start typing and as we see the text now changes okay so yes this is not the most efficient way to implement but you should also also and always consider the cases in which cases you are implementing this or that functionality okay so if you are going to have like a thousands of such type of inputs and they are frequently changed and every time you they are changed you call set model and you rewrite the entire large object it might just degrade your browser performance okay but if you don't have that much that many uh HTML elements then this is okay okay they are definitely exists the better Solutions but better Solutions generally require are slightly more advanced and require much more time and yeah I'm going to leave this as it is right now okay so whenever we type something so it changes it updates the model and we just just like this we have the always up-to-date model so option two by the way deleting doesn't work and whenever I hit the delete it actually triggered the update of the form because this needs to have type uh type of button like this 265 07:09:33,180 --> 07:09:49,760 okay let's go again inside change the type and select we have only one option click add option one option two now click save 266 07:09:50,218 --> 07:10:00,440 okay it looked like it worked here's what we sent here's what we received so we received 267 07:10:00,900 --> 07:10:33,718 everything as we should have received however we do have options right here however the type is still text but we actually received type select so now let's go and have a look why type is text selected because we have not given right here a value equals modal.type 268 07:10:34,520 --> 07:12:43,820 save that and now we have select if I just reload the page now we have selected gain okay I can change this into radio and the options are basically lost so this is something which you can um which you can basically improve so if I now switch this back into select I lost my options okay so let's add this small Improvement let's listen on type change and right here um so basically this means that we switched to a type which needs options okay but we can also access the previous type and if the previous type also needed options let's just don't do anything okay and how we can access the previous type I think that's going to be modal DOT type I saved it go in the console by the way we have an error yeah we need to specify a prop for the options all right here let's give it a key to be option Dot uuid now let's go back save reload going in for we have two options change this into radio and we have debugger we have model and model type is still select however even Target value is no radio Okay so let's do like this if the modal type let's call should should have options second time passing the model type if the old type should not have options and the new type should have options then we do this okay else if the old type 269 07:12:45,780 --> 07:12:49,940 else maybe we don't need to do anything 270 07:12:51,260 --> 07:14:32,718 okay let's let's proceed let's have a look so if I change this into radio I don't do anything I leave the types if I switch this into text the options are hidden but I guess the modal data still contains those options which is fine it's not a big deal if we leave an extra data for the um inside the question type text but of course of course ideal will be if we just don't do that and in this case we need to do an inverse operation if let's copy this part paste here and if the old type should have options but the new type should not have options we can set the new model data equals an empty object so we reset everything but the bad thing about this is that we're going to lose some something when we switch back to the select so now we have two options we're going to select I go in the text and that everything is done correctly and the option the data is basically lost but if I switch back into select then I don't have those options okay so we can even preserve that data and whenever we switch back into select we can have it if I just comment up this line and don't do it then it's going to work 271 07:14:33,440 --> 07:16:47,180 switching to text proceed then I switch back into select and now I still don't have it because because I rewrite it here okay I can check if the data is available or if inside the data options is available I can leave that so I can put an x-ray if statement if new model not new model but model dot data dot options if that exists then I don't do anything but if that does not exist then I do this okay so we have different variations to do and let's type option one then I switch into text then I switch into select and I still have option one okay so we we have basically as soon as you understand what you are doing and you just don't blindly copy and paste the codes from tutorial or from from me from the screen what you're looking right now you basically have like many options what you can do right here okay so I think this is what I'm going to leave right now let me remove it I'm okay to leave the options whenever the question type is text so that's a extra small extra data in the database but then when I switch back into select or radio I have those options available and that that's really handy I can reset the data from the backend side when I switch this into text I have those options but whenever I submit I can remove the data from the database and don't save actually this so that's that's also an option I'm going to remove debugger right here and let's actually create a few types of questions okay I'm going to create now three types of questions we have select select question and this is just a text question 272 07:16:48,478 --> 07:16:53,240 then I'm going to have a radio question 273 07:16:53,638 --> 07:17:01,820 let's set this into radio option one well like I think I can remove this 274 07:17:02,340 --> 07:17:11,660 Json stringify option one let's add a few more options option two 275 07:17:12,000 --> 07:17:40,160 option three this button is very close to the text area description so this one should probably have margin button like three okay that's better and we should probably also put maybe a horizontal line between every question that should probably done 276 07:17:41,040 --> 07:17:47,660 maybe right here and let's change this into a fragment 277 07:17:49,860 --> 07:18:00,378 save that okay not bad so have text we have select let's give it option one 278 07:18:00,718 --> 07:18:11,780 option two let's scroll down below I have radio let's add one more question which will be check box 279 07:18:13,440 --> 07:18:38,780 option one and option two and let's save it let's edit we have text we have select we have radio and we have checkbox okay and let's add also text area 280 07:18:39,420 --> 07:19:22,100 text area save it okay now we have all five types of questions five unique types of questions implemented and all of them are saved so now what else do we need to do we Implement deleting an option no I think we haven't implemented so this is what we need to do come right here on click delete option and we're going to pass an option right here let's accept an event so we do have option somewhere here we have it so let's create now this function 281 07:19:24,360 --> 07:20:00,978 function delete option we accept an option then inside modal data options I am going to find or maybe filter those options with option if the option dot uuid does not equal to the given option euid so we filter it like this and we need to assign this into model data options and then call set model 282 07:20:03,420 --> 07:22:55,978 okay let's test this click on delete delete it delete delete it and you don't have any options defined pretty nice message here let's add a few more options one two three four five click on Save and click on edit and we have all options available perfect so we have implemented the saving the survey with its fields we have implemented adding questions we have implemented deleting a question and we can save that and have a look that the question is deleted we of course have implemented adding options just right now option three we have different question types and yeah I think this is this is really good uh of course you can extend this and you can go even farther and create other types of other types of questions like Boolean which will be a single checkbox and user can agree or not on certain things in your survey you can even go further and create more types of questions Rich Text field and so on and finally if you work on this you're going to have perfect perfect open source projects which you can definitely put in your portfolio and really you can show to anybody and be proud of it so I'm going to hit on Save and now I am going to create a few real surveys and then work on the front-end side from which basically Anonymous users not authorized users can take the survey and complete that and then you're going to have a dashboard to have an overview of your existing surveys now let's start working on the public page and for this first I'm going to define a new Road in the road and that road by the way should not be part of the default layout because default layout is only for authorized users so I'm going to copy that in outside of this layout maybe at the very bottom I'm going to create it and that will be survey um with salag okay we are going to have slug for that URL maybe the URL will be survey public Slack and the GW survey view that should be survey maybe public View so inside the views I'm going to create survey public bu.jsx 283 07:22:56,458 --> 07:23:25,878 let's give it to js6 so RFC generate the component let's have it like this sorry public view we need to use these survey public view right here and then let's take this path and go in the survey maybe go in the survey View and we have 284 07:23:26,820 --> 07:23:34,160 we have right here a loading indicator then we have 285 07:23:34,680 --> 07:23:56,240 what do we have I'm looking for some kind of header which I believe we have we have this probably in the page component right we have it inside page component so we basically I want to put a link right here to open that survey in a new tab 286 07:23:56,878 --> 07:24:11,718 and yeah this is what I want to do so we have create button and we have we have surveys and create new let's let's click edit 287 07:24:13,020 --> 07:25:35,240 okay this is just title but if we go in the surveys uh we have it somewhere surveys here in the page component we have these buttons okay this is what I want to do so I'm going to take these buttons go in the survey View and put this buttons right here okay so instead of create new uh I should probably have maybe a delete survey button here and public link so let's create two buttons here well there should be a fragment inside a fragment let's put two buttons this will be public link and this is a t button and it has two but instead of two we might need href and that should be survey public in this lock okay let's change these into like this and then we will need model dot Slack 288 07:25:36,120 --> 07:25:59,360 and we shouldn't have a plus Circle icon here instead we need something else but let's let's modify this button as well delete that should be trash icon color should be red and we should have uh on click right here 289 07:26:00,478 --> 07:26:09,558 on delete okay we need to Define this function on delete 290 07:26:10,080 --> 07:26:23,100 well I should probably move this all right here up or and maybe we should have it const on delete equals 291 07:26:24,000 --> 07:27:12,200 okay now let's see how it looks like model is not defined OKAY model is not defined what do we have here if the model is not defined we have survey okay that's fine so we have survey I'm going to use survey here as well now we have three links well the design is good but they are very far from each other so I should probably change this into div and the div should have probably class of flex and probably there should be Gipper for one maybe two okay perfect this trash icon is too large I should change this into four 292 07:27:14,840 --> 07:27:31,280 and it is not perfectly aligned so I should probably go in the t button and in the base classes I should probably write items oops items Center 293 07:27:32,340 --> 07:27:44,058 okay I think that's better and this public link basically should have an external uh link which I don't remember 294 07:27:44,458 --> 07:28:20,958 like link icon maybe that's it not sure class name H4 and W4 yeah this is this is also fine so I have link icon and maybe let's give it also margin write two and when I click on this it opens survey public view which is exactly what I expected so now I'm going to go in the survey public 295 07:28:22,440 --> 07:28:25,440 survey 296 07:28:26,520 --> 07:28:43,260 public View and on mounted I'm going to make requests to get the survey by slack but first i'm going to take out slack so const slug equals use params 297 07:28:43,740 --> 07:28:48,320 okay then I need use effect 298 07:28:50,878 --> 07:29:50,420 as an mtra I'm going to use axios client get I'm going to make request survey slash maybe get by slug this the backend endpoint does not exist yet but I'm going to create that and I pass slog right here then whenever I assume that I already have the response I take out data and I need to create a survey State here and set survey use state and the default will be an empty object then I call set survey passing data okay and in template let me just output 299 07:29:50,760 --> 07:30:25,280 Json stringify survey with undefined and two okay empty object we need to implement the big Insight when I reload the page the request is made but this returns not found because we don't have backend ready yet so now let's go and open API dot PHP and let's create now a git on survey 300 07:30:25,558 --> 07:30:30,680 get by it by ID 301 07:30:31,558 --> 07:31:03,660 that should be survey controller it by ID open the survey controller let's scroll at the very bottom by the way this is only allowed for authorized users but it should not be allowed only for authorized users so I'm going to move this out but I'm going to go in the survey controller in the very bottom let's create this function get by ID we accept request 302 07:31:06,420 --> 07:31:08,958 well 303 07:31:09,718 --> 07:33:15,740 well first of all I'm mistakenly call this get by ID that should be get by slug and then here we need get by slug how do I make a request from yeah get by slack this is correct and then we need to specify right here a slug that slug can be just slug like these and then we can select this inside this gate by slug or I can change this into the this way survey column slack okay so this means that I want to take the survey and that survey will be typecasted so inside get by slug go in the controller right here instead of request I can get survey like this and in this case the framework laravel which will try to query survey of the following type by Slack okay and we can have survey right here so I'm going to Simply return entire survey so that we can check what is the actual response so I just reload the page we have 500 error git base log survey controller gitbase log does not exist yep they should be called it by slug reload the page and we have the entire survey response okay this is this is perfect however we need to check first of all if the survey is active if the status is one and if the expired date has not reached and then when to return the survey but we need to return it with the information of the questions as well 304 07:33:16,138 --> 07:35:17,180 so let me actually delete this first of all let's check if the service status does not exist we return 404 then I take the current date and I take the expired date of the survey and I'm going to check if the current date is in the future of the expiry date so if the expert date basically is passed and will also return 404. otherwise I'm going to return the survey resource with the survey and this will return answers as well so now if I just reload the page we see the entire survey basically with the questions and everything okay and now we can iterate over those questions and render them properly okay however let's go in this area public view I'm going to basically close every file now and I'm going to take data dot data and assign this into survey okay this is what I'm going to do and now let's work inside the template right here okay let's define a loading indicator as well loading and set loading let's set this into false then right here let's define one div which will be for just loading so if loading is true then we display the following div and that div will have loading text right there uh with blacks display flex and justify justify Center okay next I'm going to have second D which will be the main div and that will be displayed if the loading is actually false oops like this 305 07:35:18,840 --> 07:36:15,138 and inside there we need to display the overall information about the survey okay so let's just display the um H1 tag for the survey dot title let's create paragraph for survey dot description uh we can also display the expired date of the survey let's create another paragraph maybe this in between H1 and the description another paragraph there's going to be survey dot expire date and maybe we also need to display the image for the survey okay so let's create another div so there we're going to have an image and we're going to have survey Dot image underscore URL 306 07:36:16,620 --> 07:37:16,320 okay this is the survey overview let's wrap this in a div and that you might need some classes but let's leave it as it is for now and then down below we need to start iterating over our questions so let's create one div and then we need to start iterating our questions but we for each question we need to create a like a question uh viewer component something like this okay so let's take um survey data options uh no excuse me survey questions map and we have question here then 307 07:37:17,040 --> 07:37:25,280 then we need to render some kind of component I'm going to create new component 308 07:37:26,218 --> 07:37:54,900 that component will be survey like a public question view Dot js6 let's generate a boilerplate code and let's use this public question view that should accept right here question 309 07:37:55,440 --> 07:38:14,540 and and what it might also need an index so let's accept both here and we're going to pass a key which will be question Dot uuid we're gonna pass question 310 07:38:15,298 --> 07:38:24,320 and we're going to pass index foreign index here 311 07:38:27,120 --> 07:38:48,680 okay now let's have a look we have the image which is huge we have title we have um expired date we don't have description for that survey so basically we have the markup but we need to apply some styles to that 312 07:38:48,958 --> 07:40:34,760 well I'm going to make this Steve display grid and greed calls six maybe and this one will have like let's give it a margin right and let's wrap the following elements into a div and let's give this div um call span five okay I want the image and the overall information to be next to each other um like this maybe but let's give more classes like the H1s to have text like a three excel in margin bottom three and the expired date as well as the description will need to have probably text Gray like 500 and texts small let's take those classes for description as well so we saved it okay here's the expired date we can write even expire and date like so and then we have the description by the way let's give it some description I'm going to generate lorem ipsum code take this and paste it in the description click on Save come here and refresh refresh okay something is wrong um cannot read properties of undefined reading map what happened 313 07:40:39,660 --> 07:41:29,780 okay I think I know what happened so before the response is received before the response is received we try to iterate over survey questions but the survey questions is undefined and we haven't implemented this loading yet so if we Implement loading then we won't have this problem because whenever the loading is false now we might still have that - problem but let's still Implement - loading set loading equals true and in then we call set loading equals false and inside catch as well we need to we need to set loading equals false 314 07:41:34,920 --> 07:52:02,660 okay so yeah this this doesn't doesn't fix the problem because before even before the request is made the loading is false and the code execution comes right here and then we have a problem so basically we need to specify questions to be an empty array right here okay and if I just reload the page now we don't have the error let's specify a margin bottom three here and here as well okay the the design might not be like a excellent one but that's not that's not a big deal at the moment well I'm going to wrap everything inside a form because finally we're going to submit that form okay so and let's give this form a container class and maybe margin X Auto so that we have this form in the center okay and now we have four questions and I think now it's time to implement the each individual question now let's continue working on public question view js6 component and right here I'm going to also accept answers changed prop which will be function and from this component we're going to call this function whenever a specific answer is changed for some question now inside the template I'm going to create fragment inside of fragment we're going to have a field set and I'm going to put HR as well like a separator or horizontal line between multiple components between multiple questions okay inside the field set we're going to have div and Legend with some Talon CSS classes based classes and we're going to display the equation index and the question text and we're going to have also question description and down below we're going to have additional wrapper div element and inside there we're going to have different question types okay we have file question types and we're going to render each of them separately with its own area like we're going to handle the select we're going to handle radio we're going to handle checkbox text and text area if you want to extend this project and go step further you will you can just easily add a new if statement right here if the question type equal something then you can render your own markup right there and your own functionality okay you can even go step further and create independent components react components for each question type like question type select or question type radio and then you can render that independent components right here okay I'm just giving you an idea how you can extend this project and go so farther okay now let's start with the question type and right here I'm going to have a div and select so I'm going to type all the title ancestors classes it's it's pretty obvious what I'm doing right here next we need on change event handler on this select so whenever a user chooses some type of answer from the select we need to do something we need to save this somewhere okay and this is the case we're going to call answer changed and that answer change is a prop even to this component okay it's it's a function actually and then we're passing the even Target value which is the answer which was just selecting okay let's go a step further and we need to render the options inside the select the first option will be please select like a placeholder of the select and we're going to iterate over question data options and then we're going to map each option into an option HTML element with the key and value and the text will be also the value okay and I think that's it for this select and let's go down below and now let's Implement radio so right here we're gonna just start iterating over our question data options and we're going to map each option into a input type radio so we're going to have a wrapper div element with the key and some classes and inside there we're going to have input type radio Okay this will have also ID option uid so each option has its own unique uid and I'm assigning right here ID because I'm going to create down below a label and that label will have four on this input on this input with this ID so that whenever user clicks on the label it's gonna select the simple type radio okay we're going to have name right here as well and that name needs to be the same for every option because you should be only be able to select one option from the radial list okay now down below we're going to have a value we're going to assign what should be the value actual value for this particular radio button okay and down below uh we need to listen to the change and whenever change happens then we took a game called the answer changed with the selected answer down below we're going to have like a label tag which will have four as I mentioned with the option uid some talents classes in the option text okay let's go on the next question type this is a checkbox again we're going to iterate over like a question odd data options then we're going to have wrapper inside there we're going to have input type checkbox uh we'll listen to change and in this case we need to call checkbox changed because checkbox is at the moment the only type of question which has which have um has has is correct which has multiple answers okay and we need to handle checkbox slightly differently we don't have this on checkbox changed yet but we're going to create that soon and I'm going to declare this at the top now Oops I did something wrong okay now let's create a label right here which will have four with the option uid and text and I think that's it for the question type checkbox okay the next question will be text and that's pretty straightforward we're going to have input type text we'll listen to change and call answer changed and we're going to have text area it's also very similar to text we want to have text area tag with unchange event handler and we call answer changed I think we don't do anything right here in terms of template but we need to handle the case when we have a checkbox so we need to create this that on checkbox change okay how we're going to do that inside the react component and then I'm going to declare a variable called selected options and that will handle that will contain all the selected options from the checkbox type of question okay I'm going to solve the clear on checkbox change function which accepts option and event okay and then I'm going to check if the even Target is checked so if the checkbox was checked then inside the selected options I am adding the option uid however if the checked is false then I'm removing the uh this particular given this option from the selected options okay so this is actually what I'm doing right here okay I think um so far is so good and finally we're gonna call the answer change with the selected options and just like this the appearance component will know whenever the question is changed whenever a user answered something like Mark the checkbox or selected the radio or choose something from the drop down pairing component will know now all that okay and I think that's it right here so I'm going to go now in the survey public View and right here we're going to make some changes okay so first we need to listen to the answer changed because we're triggering this answer change many times from the public question view next at the top I'm going to declare an answer's object okay this is standard object is not a state so we're gonna gather all the answers right here inside the object next we are going to create a function as we're changed which inside which we accept the question and the value and then inside the answers object we put the question uid corresponds to the given value okay and just like this finally the answers object will contain the question ID question uid will be the key and the value will be all the values all not all the values but the value of that particular question okay and I'm also I will also want to have a look what's the actual question and value so I'm logging this right now at the moment okay and then right here we're going to create a submit button because we don't have this button at the moment in This Server public view that's a standard button with type submit and a lot of Talon CSS classes okay and at the top we're going to also listen to the submit of the form and we call on submit function which does not exist yet and let's define this on submit function which accepts an event we're going to call prevent default and finally I'm going to log the answers all the answers what we have gathered now let's have a look in the browser what is the result okay the result looks promising we don't have any errors do we have oh we have probably let's reload the page okay we have one error that comes from the class name uh and yeah so basically um right here in this public question view I think in many places I'm just using classes okay so I have this markup HTML basically and I prepared this rear component from this markup HTML and I simply didn't rename the class in the class name so we can do this right now easily with replay find every class and replace with class name let's do this we have like 14 matches this is the first one let's replace one by one because I don't want to replace anything else which is not actually CSS class so let's start from here replace the place let's follow 315 07:52:02,940 --> 07:53:47,000 okay we are almost done here we go okay we replaced all and the next error I think was on html4 so we are using four but we should be using html4 anything we have in our error which probably comes from this survey public view so I think on the button right here we are using class again but we should use class name so if we just reload the page we should only see html4 okay that's that's another error which we're gonna fix right now but let's fix this html4 at the moment so I'm going to go right here search for four equals replace html4 equals one and two okay and one last thing is which we need to fix is this um somewhere this is coming from the public question View each child in the list should have a unique key so somewhere we have a loop but we don't have key so here we have key for the for the checkbox we have key for right here we also have key here we also have key where do we have missing key okay we also have key okay so let's search for if we are using map somewhere without key 316 07:53:47,340 --> 07:53:53,780 we have it here we have it here 317 07:53:54,718 --> 07:54:14,958 so it looks like we are using this um basically everywhere and I'm not sure where this errors come from but if the air is there um I'm sure that but I just I I missing something and um we have to find this out 318 07:54:15,420 --> 07:55:32,120 okay so now let's debug our problem okay before we jump into this I want to prove in this error so such type of Errors basically are kind of annoying because it looks like you are doing everything correct but you are not because the error is there so and these type of problems are excellent problems to improve your debugging skills because you don't know what to do because it looks like you are doing everything correctly but now like there's an error and you don't know what to do okay so I'm going to go ahead and like um using binary search algorithm which is which is the one of the most amazing algorithms simply stand amazing algorithm I'm going to reduce my problem search area so basically I'm going to remove these three questions okay leave only select in radio I'm gonna just remove this okay now if I reload the page okay I still see I have this error so now I'm going to remove both of them again now let's have a look I still have this error okay so the problem is somewhere else okay where is this problem 319 07:55:43,978 --> 07:56:08,898 okay each challenge list should have a unique key prop okay something strange going on because we don't have any Loop right here if we just remove everything from here do we still have this problem we still have this problem okay we have empty component but the problem is still there 320 07:56:10,860 --> 08:01:31,040 sorry public view okay the problems come from this components okay it's obvious not from this component so I'm going to undo everything right here oops html4 and let's come and let's now search for um dot map okay we have key right here okay this is the only place we are using map we are iterating inside our array and we are using key right here but does the question has uuid or ID that is that is I think that is it let's change this ID because I think for the question we have ideas not uids let's just reload the page okay again we have four any tasks if we mean html4 let's search because I undo too much h tml4 just like this now let's rule the page and here it is okay so just like this it was a small kind of annoying problem but we found where the actual problem was and the actual problem was right here because I was using like a uuid which was undefined and we were giving the same key for the public question view component and that's why you react was complaining okay you have to find your problems you have to improve your debugging skills okay so far so good now let's choose let's go in the info because I want to see logs right here and I'm going to choose now option two right here and here we have so this is the question and this is the actual chosen value okay if I replace and change something else we have the different option then I'm going to choose right here option one again or option two we see every time it is printed let's clear up the log now I'm going to choose one two and four okay and as you see we have list of UI IDs and those are list of options what we have just selected okay and finally I'm going to type something like lorem ipsum and as we see we get this triggered as well and finally if I click submit we have white undefined which is which is not what we expected okay so let's have a look so I want to check another option and the question has ID right here okay this is an actual question and we have selected options right here now if we go into a republic View and find the place again right here I'm using euid that should be ID so just like these uh we should now fix all the problems I'm going to select now option one option two right here three three four and five and some lorem ipsum text now let's click submit and now we have on question 13 we have option one on question 14 we have option two on question 15 we have the following option selected on question 16 we have lower M ipsum I think at the moment we have only four questions and this looks exactly what we expect okay we have prepared all the data which we just need to send to the back end and save that information on the server side now let's open survey controller and right here at the maybe at the very bottom of the survey controller I'm going to create a new new method which will be to store the store the answer and I'm going to call this method like store answer maybe store answer and right here we're going to accept some kind of request and we are going to I'm going to create basically a separate class for this request so let me make this like an empty empty function and I'm going to accept them I'm going to create my own request class for this and we can also except right here a survey on which we are making uh the submission okay so now let me bring up the terminal I'm going to create new terminal right here and I'm going to generate the request class PHP artisan make request that's going to be store survey answer request okay and let's hit the enter okay that was generated now right here I'm going to accept accept store survey request no stir survey answer request this is what I want that's going to be request variable and we're going to also have a survey right here as a survey okay so I have all the um all the parameters of this store answer method and now let's create the sorry now let's create the actual method 321 08:01:31,620 --> 08:06:29,958 first of all let's get all the validated data from the request class next we're going to create survey answer and the survey answer has survey ID start date and end date okay at the moment we are making it simple and let's say that we are saving the starting end date to be the same but the actual database gives us possibility to modify the code so that you give possibility to the user to start the survey today but completely tomorrow and for kind of analytics tracking or to make this complex to make this project a little bit more complex and interesting you can also Implement that functionality like save the user information somewhere in the temporary storage uh like based on the based on some kind of identifier of the user maybe in the cookie but also registering the database that the survey answer was started like users started answering that survey and whenever a user clicks the submit button and finish that survey then you can set the end date okay so you can have like a difference between the end date and start date and have kind of analytics that the user needs on average like 15 minutes to complete the survey okay that kind of information is basically really useful and you can again go step further and create that kind of functionality because because like you need to put all your own twist on on every project and that helps you a lot to put your portfolio put your uh project in portfolio and make it unique okay let's go let's continue I'm going to stop talking right now and right here we're gonna just iterate actually I cannot stop talking right now um anyway so we're going to iterate over validated answers and we know that the answers is an object and it has key question ID and actual answer is the value so and then we get the question ID we get the given survey ID and we actually select the question so this is a kind of a small security mechanism that we need to make sure that the question exists okay and if the question does not exist we return invalid question ID if we get some random number right here then the we just throw that it's an animal equation okay now let's continue and the data we're going to prepare the data to save in the database the data will have like survey question ID it will have survey answer ID which is the answer we just created right here and it will have the answer which will be Json okay if the answer is an array we uh just Json encode that otherwise we just provide the answer and yeah for some reason if you get the answer already encoded as Json string then is array will return false and this string will be saved as a string okay and finally we call survey question answer create we pass the data this Returns the question answer which we can return into the client but we actually I think don't don't care is these right here and finally we just return an empty response that uh with status quo 201 which means that the record was created but we don't have any answer to return everything was successfully completed okay and after this call we need to import two classes this is the survey question answer and Survey answer so at the very top of the class let's import the server equation answer and Survey answer okay and just like this we have our action ready now let's go in the store survey oops question answer and Implement that so first we're going to change these authorized into true let's scroll down below and right here we need to Define rules actually the Only Rule we need right here is answers which should be required and it must be array okay we don't need anything else right here next is to open api.php the roads file and parallel down below I'm going to create one post wrote approach post it's going to go on survey slash we are going to pass right here the survey okay we can pass this as an ID or as a slack as we want but I'm going to leave this as an ID at the moment so survey and then we have like an answer okay here and then we need to specify the controller sorry controller class and store answer 322 08:06:30,540 --> 08:08:05,180 okay so we have the road ready we have the controller ready we have the request class ready I think right now we can make requests from the react and see if the response will be saved in the database inside on submit function let's use axios client and make post request the URL will be survey slash we're going to specify right here the survey ID let me change this into big ticks and I'm going to use the survey which is basically inside the state so survey dot ID answer and we're going to provide right here the whole answers and we might also need to provide the sorry idea but we have survey ID right here okay so we just provide right here answers but we need to provide this as an object answers like this okay let's now listen to then we have the entire response let's actually destructure the response and take out data from there but we actually don't even hear the data we hear only the status code so let's take the entire response and I'm going to put debugger right here to see what we get okay and what else 323 08:08:05,458 --> 08:09:35,840 so whenever the survey is completed and we get the successful response we also need to show user um like thank you message thank you for participating in the survey or something like this so I'm going to create another state that will be survey survey finished Maybe survey finished and set survey finished use state by default will be false okay and then right here I'm going to call set survey finished why do I have this I in uppercase let's rename and refactor this sorry finished I'm going to give it true okay and down below let's identify the play so here we have the form and maybe inside the form maybe down below right here maybe maybe before we render the questions okay and even before the submit button maybe we are going to show thank you message so basically let's create now survey finished if the server is finished then let's render the following markup oops 324 08:09:36,120 --> 08:11:49,620 okay so that should be that should have some Talon CSS classes like let's give it padding uh why putting Geeks um let's give it PG Emerald uh maybe 500 let's give it also text white and let's give it also fixed width like 600 pixel Maybe square brackets and let's put this in the center remix out AMEX Auto okay inside there let's just put I just put a message thanks thank you for participating in the survey that's it however if the server is not finished we are going to render the rest of the HTML so let's put color braces if not survey finished oops and then let's this uh we will need I think fragment right here okay let's put this oops I am mixing something we have this template and inside the fragment we just put the old markup and now we have these Divo the questions in the button so now I save this and now let's have a look now let's test this so let's just reload the page we don't have any errors okay I'm going to select option one option two three and test let's go in the network click submit okay the request was made we have an error survey ID needs to be added inside the fillable property of this survey answer okay I think there is very very obvious when to open survey answer and we need to add protected 325 08:11:50,478 --> 08:12:27,740 peelable right here in a survey underscore ID now let's retry another error column not found dated it in survey answers yeah we need to disable updated add column answer the answers uh const I think it is a const updated at uh equals false I believe it it is like this 326 08:12:29,940 --> 08:12:37,700 because I remember oh but we can we can have a look two few arguments to function 327 08:12:40,680 --> 08:13:15,200 okay I think this is uh this is this particular problem okay so we need to I don't remember what's the actual name of this column like PHP stormy basically gives me very very good Auto completion about this updated eight column maybe no okay let's find this out laravel disable updated it on model 328 08:13:18,840 --> 08:13:43,160 we need to set this to null why is it this false you know okay we'll set this to now now I'm going to click submit and we have the same problem but now on create it so it looks like we don't have created it on the survey as well so 329 08:13:43,760 --> 08:13:52,218 created at reload why did I reload not sure 330 08:13:53,940 --> 08:14:19,878 click submit we have another error survey question ID needs to be added in the survey question answer so let's open survey question survey where is survey question answer question answer and let's add protected viewable 331 08:14:20,160 --> 08:14:25,040 survey question ID 332 08:14:25,500 --> 08:15:16,700 click submit again and another error so the answer ID needs to be needs to have a default okay what's that survey answer ID doesn't have a default value inserting to survey questions survey answer ID okay but we provide the survey answer ID I think so if we go in the controller we have a sorry answer and provide survey answer ID here don't we I think the survey answer ID needs to be ideal so in the fieldable and the answer also needs to be added in the fillable of this model okay so we add survey answer ID and answers now let's save this 333 08:15:17,160 --> 08:15:29,298 and we by the way we have the start date and end date and a survey answer and I think we need to add them here as well 334 08:15:30,240 --> 08:17:42,200 now let's click submit again we have another error I don't know how many years we have uh field answer doesn't have a default value I think I added answers but it is an answer so right here we need answer click submit a thousand times and we have successful response status 201 which means that the something good happened and now let's check inside database hpmi admin let's by the way proceed and we have this message as well huge padding uh laravel react I think this is the database we are using and in this survey answers we actually have multiple answers because yeah while we made a multiple requests a few of them were successful and we have I think this is the latest one with id4 and if we're going to survey question answers here we have the sorry answer id4 and for the fourth question those are the answers like for the question 13 we answered option one for the question 14 we answered option two for the question 15 we answered the following uids by the way these probably should not be even new ideas this should probably be an actual option text because we are always saving options as a text right here and they would have tests here okay why don't we just save this as a normal text and we have dates now let's go in the react and change these I'm going to open survey question View and on checkbox change we have the option and let's use option text 335 08:17:43,820 --> 08:17:56,298 like this okay now if I reload the page and choose some options 336 08:17:58,798 --> 08:34:56,478 and click now submit we get successful response and if I just reload the page we have two three and four is options as text options okay this looks this looks exactly what we how we wanted um I mean the design is something which needs to be some rework and I appreciate if any of you love making changes in design of someone else's code and you can have a look at the my code in the GitHub repository and make changes in this code but yeah my main my main goal is to focus on the implementation and functionality from front to back design is a secondary for me but we still have um something okay so this is amazing now let's start working on the dashboard we're going to implement dashboard and we're going to implement a couple of cards on the dashboard we're going to show total number of surveys to the user as we're going to show the information about the latest survey we're going to show also total number of answers the user got and we're going to show latest five answers user received on every survey user created okay and let's start implementation from the backend and I'm going to create dashboard controller in laravel now let's actually create new terminal let's open your terminal and I'm going to run PHP artisan make controller dashboard controller and hit the enter the dashboard controller was created now let's open dashboard controller okay we're going to implement a couple of methods right here I'm going to also create two additional resources one will be survey answer resource so let's execute PHP artisan make resource sorry answer resource hit the enter and second resource I want to create will be survey resource for the dashboard okay so I'm going to return the survey information on the dashboard for for example for the latest survey so let's call this resource survey resource dashboard let's hit the enter okay resources have been created now let's implement this index method so at the moment we need only one method which will return all the information at which the dashboard might need but you can even split those these data into multiple different methods and you can call multiple requests from the react and fetch one information at a time okay in this in in this case you can also create a different small loading indicators for each the data you receive okay I will explain later better or what I mean but now let's start implementing the index method so right here we need to accept request and then we need to return some kind of array from this method and that associative array will contain all the data we need on the dashboard then I'm going to get the user information from the request because we need to fetch the information for the currently authorized user okay next we're going to get the total number of surveys by executing the query survey query where the user ID corresponds to the currently authorized user ID and then finally we call count which will return the total number of surveys the user has ever created next is the latest survey so we get survey query where the user ID this is basically a like a base query for every Everything almost everything we're going to return from here the filtering by user ID this is crucial right here we're going to make sure that we only show user the information he actually created or she okay then we're going to call latest by creating it so we're going to get the latest created in the first so this will return the latest survey next is to to get the total number of answers in this case we start query from the survey answer then we join this into surveys by the survey ID and then we add again like the where Clause where we check the surveys user ID must be the currently authorized user ID and finally we call count so this will return total number of answers all my surveys has ever received okay and the final is to get the latest uh five answers so in this case we start again survey answer then we join this into surveys we added this where clause which is the identical what we did so far here and then we have the order by end date the end date now is the end date of the survey answer so we need to get the latest five answer so we add end date right here then we'll limit this into five and finally we're going to return the instances of the Surry answer so we just return everything from this survey answer okay so we have all the data we need now let's return this from this from this function we're going to return total surveys which is the total variable we're going to return the latest survey however the latest survey might be even now if you logged in to your dashboard very first time if you have not created anything latest survey will be now so we're gonna check right here if the latest exists then we return survey resource dashboard which we just created and the latest variable is passed into the resource okay so this is the resource this is the resource we're going to return from here is the latest exists otherwise we simply return now then we return total answers and finally we return the latest answers which is a collection of the survey answer resource okay so we have our action ready and what we need to do is to import the necessary classes right here so at the top I'm going to import those classes okay so far so good now let's open those resources like survey dashboard resource survey dashboard resource and let's implement this let's open right away um survey answer Resource as well here it is and we need to implement actually uh both now let's start implementation with the survey resource for dashboard and first I'm going to remove this prn2 array and we're going to return new empty array from here and here we need to return the following properties we need to return ID image URL however we need to check if the image is ex if the image exists on the survey we're going to return the URL of that image otherwise we simply return null okay we will return title we'll return slog we're going to return the status as well and we're going to return the created it but formatted in the following format from here we will need expired date and we're going to return the list of not the list but the number of questions for that specific survey okay and finally we're going to return number of answers for that specific survey and I think that's it right here we are going to import that URL which is facade so we're going to write use at the top right here okay and our survey resource for dashboard is actually ready so next we're going to go in the survey answer resource and we are going to again remove this and return an array we're going to return ID we're going to return this survey we pass this survey into survey resource but whenever you do these make sure that the survey answer has a relationship to the survey okay this is something we need to do if we haven't done before okay the end date right here and I think that's it now let's open survey answer model and right here we need to add belongs to okay make sure you have belongs to Method edit right here which uh has a reference to the survey without this belongs to basically you won't be able to get these survey inside the survey answer resource okay and you can also do uh like vice versa we need to go in the survey PHP and we need to iterate here answers relation to answers with as many because we are using answers in the survey resource dashboard I guess right here okay so you make sure add this method answers right here in this survey PHP and Survey answer resource and in inside the server answer you need to add it belongs to Let's import this survey right here okay the survey make sure that the survey is actually either imported or I think we don't even need to import it because survey and server answer are in the same namespace so no need to import anything okay so we have the dashboard controller ready we have the resources ready we modified the survey PHP and Survey answers PHP models to have the proper relationship to each other and I think the only thing which is remained on the backend side is to open um api.php and right here we are going to add get request to the dashboard so let's create wrote we're going to make gate request on slash dashboard we are going to use dashboard controller for this and the method will be called index okay make sure the dashboard controller is imported at the very top here it is and just like this we have the backend ready now we need to open dashboard.jsx and we are gonna work right here on the dashboard component we're going to show four different information four different types of information and I'm going to show them as four different cards why don't we create a component for the card in the components folder so I'm going to call this dashboard dashboard card.jsx give this the component let's generate boilerplate code and we're going to implement the HTML right here first I'm going to accept two props first is the title and second is the children's children will be everything what will be rendered inside the inside this dashboard card then I'm gonna create a div with the Italian CSS classes which which will which will also have animation and then inside there I'm gonna print the title if that's available but I'm going to print the title inside the H3 tag with the following title that since the classes and down below I'm going to print everything uh every children okay now let's go in the dashboard and right here we're going to import the dashboard card and we're going to also import additional few things because we will need them in the template okay I'm going to import use effect and use state I'm going to import access client because we're going to make requests to the backend to get the information I'm going to import the t button component as well which is the but the component we created I'm going to import icons from hero icons and I think that's it okay then I'm going to Define States for loading I'm going to show a loading text until the data is actually loaded I'm going to Define State for the data as well and then using use effect I'm going to listen when the component he did the mount and I'm going to make a request okay but first i'm going to set the loading true but I think this is also not necessary because by default the loading will be also true okay we're going to make requests to the server we are going to get the response and set that response first set the loading State into false then set the response into data and we're going to also catch that and just disable the loading okay and just like this when the request is made and we have successful response the loading indicator will be stopped and we will have the data collected okay now let's focus on the on the component so we're going to have right here the title dashboard and inside there we're going to check if the loading is true we're going to show The Following text loading if the loading is false we are going to render under the like of a container which has display grid for cards okay and right here we're going to have four different dashboard card components total surveys we're gonna have total answers we're going to have latest survey and latest answers okay and let's focus on one card at a time so now here we're gonna show just the total surveys which is uh the just the total service property of the response which is returned from the backend okay data right here will be the actual data returned on the API endpoint and again if we open dashboard controller we see that we return the following associative array in total surveys will be that okay scroll down below and next we're going to implement the total answers which will be very similar we're going to get the data.total answers down below it's it's a little bit more interesting now we're going to show the information about the latest survey okay so we're going to check if the latest survey exists again it might not exist and if it does not exist we're going to show some kind of different text that you don't have any surveys created or something like this but if it exists we are going to show an image of this latest survey we are going to show title of that we're going to we're going to show the date when that survey was created also the expired date when the survey expires we're going to show the status of this array whether it's inactive or draft and we're going to show the questions how many questions that survey has and answers how many answers this survey received so far I think that's a very good and overall information about the latest survey now down below we are gonna also um add like two buttons one will be to edit that survey and there's going to be the t button which we created with the talances icon hero icon and the that links to the survey page and second will be to view answers okay this is this I I did just for the demonstration purposes but it's not going to be implemented this is something I'll leave uh to you as a challenge to implement a different page for the surveys okay and now at the at the very bottom like before or after we check the latest survey if that exists we return that information otherwise we're going to show some text that you don't have surveys yet now let's focus on another card which is the latest answers so right here we checked if the latest answer is the length if that exists we're going to create the container with the text left class and we are going to iterate over our latest answers and create components okay we're going to have right here and I'm going to use a element at the moment but again uh like this is something which probably should be implemented in the future so whenever you click answer to be able to see what answers the user actually took when passing the survey okay so we're going to display the survey title on which survey the answer was made the date when the answer was made and I think that's it okay we just display that information right here and down below we're going to check if the data latest answers length does not exist we are going to show you don't have answers yet okay and just like this we have implemented the dashboard component with the with the template and basically everything what we need I think it's time to check that in the browser so let's open the browser and let's have a look okay we have information can read properties to find a fine reading length if we just reload the page we get this error that comes from the dashboard and let's check we let's check first of all let's check what's the actual response coming in network so I'm going to inspect that and go in the network reload the page and we see some kind of problem the problem is the course problem okay the request was not successfully made uh we probably have some error we're going to open the terminal and let's have a look 337 08:35:01,200 --> 08:35:08,718 okay APA PHP Artisan service running on Port 8000 338 08:35:09,780 --> 08:35:39,680 okay let's zoom out slightly we don't see any information which indicates me that we have some kind of error okay we need to have a look what's the error in the logs file so let's go probably in the let's collapse everything let's go in the storage logs a lot of a lock and let's scroll at the very bottom and see what errors do we have 339 08:35:40,860 --> 08:43:27,262 um I'm going to start from the first line what's that okay parse ER do we have some kind of syntax error I'm going to clean up everything from the larval log and just reload the page okay so we have some kind of syntax error as it looks like okay probably I missed something like a semicolon or something let's have a look let's open this survey resource dashboard not this one to import the survey resource dashboard I think we have imported that okay here it is semicolon is missing right here and that's why we have this error let's save this and now let's reload this okay we have probably this error on second Resource as well survey answer resource here it is okay by the way vs code doesn't give you like it it's basically puts a red underline right here but there is not very clear like I would like to have like much much larger red error that we have something missing but anyway so we're going to put semicolon right here reload the page okay we still have some error now let's have a look in the larval log gain we need to debug our problem I'm going to clear up everything from the logs reload the page again and we have syntax error again and that error comes from where API okay it comes from API dot PHP okay again semicolonials missing here I save that reload the page now we have 500 this is not course error which means that we have something wrong in the logic so let's clear up again everything and just reload the page and have a look belongs to must become valuable okay okay the problem is if we go in the survey no sorry in the survey answer basically right here it should not be belongs to there should be answers that's it that's belongs to was a like silly okay reload the page one additional error country properties of null reading title okay it looks like we got some kind of answer from here okay latest answers uh but each survey basically um doesn't doesn't exist for each answer okay but it should exist now what's the problem in the sorry answer that should observe me my mistake another stupid mistake by me okay reload the page and we have something promising okay let's have a look so total surveys is one total answers is 5. the latest survey is the these and we have the date expired date what's the status how many questions that survey has What's the total answer is made on that survey we can click on the edit server which opens the survey edit page we have all the questions right here you know what I'm going to go ahead and add one additional question right here test Let It Be text no matter I'm going to save this or have this notification we went to the list let's go on the dashboard and right here we have now five questions on the survey okay if you click edit survey then click public link we can pass that survey I'm going to choose a couple of options right here I'm going to type test and test right here click on submit we got successful response not very nice but it successfully responds still I'm going to go in the dashboard reload the page now we have total on Source equals six okay and at the very bottom we have the latest answers made on that survey okay so this answer by the way is uh not the quite accurate data because we are testing this is the very first answer probably we made on that survey maybe not the very first but one of the first survey answers we made on this um until uh like before we had the full implementation on the saving the answers okay and yeah just like this we have implemented the dashboard which in my opinion looks not bad okay and I think right now is the perfect time to hit the like button and subscribe to my channel if you are not yet and if you enjoy this video so far this is how our dashboard looks like there are a few things we need to change in the dashboard to make this looking a little bit better so in fact if you open our dashboard j6 we have the dashboard cards right here which accepts the class name but these class names are props of the dashboard card component these class names are not an actual HTML class names that's why if you actually inspect any cards right here you won't see these class names added to those cards okay and that happens because simply they are not assigned they are not given so to make this working when to go in the dashboard card and create another appropriate here class name let's take this prop let's make it by default to an empty string so let's take this prop and I'm going to change the classes how they are given like these and let's concatenate these with the class name so basically I'm accepting a prop class name and I think we need to curl the braces here so I'm accepting a prop class name I'm taking that and concatenating it with existing class names any classes which we are given from the dashboard will be additional classes to an existing classes okay I think this looks fine now let's open dashboard and have a look okay now few things have been changed so we we see the latest survey on the left side we see total surveys and total answers right here and we have latest answers I think this looks a little bit better okay remember if we undo my changes how this looks like okay here I think I have an error okay here it is so this is how it looks and this is how we change that I think this is much better and this is also responsive so if you just uh reduce the screen size it's going to show two columns and then it's going to show one column and you have the overall information you might need okay that's a small addition which was required it additional thing additional small small thing is that at the moment all surveys have animation but they animate all together okay if we go in the dashboard j6 we see animation delay which is which is actually different which should be different if it's not different it should be different for a few of them like here on the first card we have animation delay 0.1 second here we have animation delay 0.2 second here we have again 0.2 second and down below here I think fourth card which is 0.3 seconds okay this is not actually taken if we again inspect these card and have a look so this is the card which here's the - card which does not take style okay so - why don't we 340 08:43:28,138 --> 08:45:05,718 let's accept a style right here as well and use that so I'm going to make these as a empty string and then right here let's apply Style is he received style variable so I'm going to save these and do we pass the style properly let's have a look so I think we do pass it properly now I save this and have a look uh we have another style Perfect Space okay so we need to change these from string into an object so instead of writing these we're going to make these inside curl braces okay and instead of Dash value here we need camel case version and right here we should make this string okay this is valid actually we need to convert this into an object so we are using curly braces here to indicate that we want to bind the property and then we're going to wrap this selection into another curly braces which indicates that this is an object this is an object we have a lot of red indications here we have some kind of error at the moment which is not a big deal we can actually fix that so let's now let's collapse these uh card I think it's not collapsed because there are a lot of Errors so basically I'm going to copy this line let's scroll down below we have another dashboard card which has 0.3 seconds so I'm going to change this into 0.3 uh let's move up we're going to have 341 08:45:06,958 --> 08:56:10,500 here we have again 0.2 second the class name is extra here and let's move up and here we have 0.1 second again however I think this is not uh this is not quite accurate according because we have some kind of error I think the reason for that is we have an extra quotation mark here okay I think that is the problem so we need to remove this we don't need that here we go we have only one error which is right here so this because we copied the incorrect code now we saved it and now let's have a look here we go here we go we have nice animation one after another like the middle one then the left one and then the others okay that's that's like a small Edition but I think it's really it's looking nice in my opinion here's my hostinger age panel and from here we're going to claim the domain and set up the virtual private server and install our project I'm going to click claim my free domain whenever you purchase and you're going to have the domain you can claim it from here and let's choose the name like react Dash surveys and I'm going to choose the dot com reactservice.com let's check availability okay it looks like it's available I'm going to claim the domain from here I'm going to add new profile or use existing I'm going to use existing click finish registration click continue and our domain is actually ready let's open new new tab and type react surveys.com if you see page like this it means that you have successfully taken your domain now we need to take VPS and configure that I'm going to go on the dashboard and I have a couple of VPS planes and whenever you purchase the virtual private server plan on hostinger you're going to see these on your dashboard okay and I'm going to click this VPS server plan too and let's set this up I'm going to click Start now then I'm going to choose the location where I want the server to be I'm going to choose USA click continue here we have three options we can install OS with control panel some kind of game server or plain OS in this case I'm going to choose play noise and I'm going to install everything using terminal that's going to be very interesting then I'm going to choose the latest Ubuntu which is 22.04 at the moment I'm going to click select and continue right here I'm going to choose the VPS name and I'm going to also assign what should be the SSH password for the server as the name of my VPS I'm going to call this same thing whatever I have given to the domain so react surveys.com that's going to be the my VPS server name for the password I'm going to choose something which is very unique and very secure if you know how to authenticate with the public private keys I really recommend to edit right here but I just don't want to cover in this video and let's skip that so I'm going to click save and continue and here's my overall information and I'm going to click finish setup it's going to take few minutes until this process is finished once the initialization is done you're going to click manage server and you'll be able to see the following screen so from here we can manage our server we can have a look at the VPS access some plain details we can get the IP we can go in the server usage and make even like reset the operating system completely so first I'm going to copy this IP address and open in a new tab and hit the enter that's going to give me Apache 2 default page so that shows that our server VPS server actually already has Apache installed okay that's pretty cool we need to access our server using SSH and here we have the Assange command we just need to paste in our sh client and execute that but we also need to connect our existing domain to this VPS server now if we actually go to the domains right here and then find the domain we just purchased that's react surveys.com click right here so here we have the name servers if you purchased the domain on somewhere else you will have possibility to manage your name servers on that place like if you purchased it on codedy or somewhere else you can manage name servers from there and the main thing is that you need to point the name servers to the hostinger virtual private server name servers okay so you have to click change right here not right here but in if you purchase the domain on hostinger there's nothing to do um okay but we I think we just need to switch this into housing and name servers which is recommended and and this is how it should be but if you want to move your domain somewhere else like you purchase the domain on hostinger and one hosting on somewhere else then you need to change name servers right here but if you purchase the domain somewhere else but the server or hostinger you need to do something something similar in your domain provider okay this is very important and if you purchase the domain somewhere else these are the DNS servers you need to specify in your domain provider okay at the moment the DNS is okay we don't need to do anything but we have to manage DNS records right here in this domain here we have a couple of DNS records and if I scroll down below we see cname record which points to www.reactservice.com if you scroll down below we have a record which points to some IP address this IP address address is what is displayed at the moment when we type react surveys.com in the browser okay this is the different server which we don't want so I'm going to click delete right here we need to map the uh the domain into a different IP address and when I open VPS in a new tab and right here we're gonna grab the IP address and create a record so let's click these react surveys then I'm going to give the IP address copy that go in the DNS name servers and create a record I'm going to leave this name at which indicates the root domain and then when I paste right here the IP address on which I want to map this domain okay and I'm going to click add record it might take several seconds meaning it's hours depending on many other things and you need to constantly check your domain reactservice.com in the browser just to make sure that it's the mapping to the IP address successfully works so if we open this in Incognito and hit the enter we should see the Apache page and if you see the Apache page it means that the domain was mapped to your server okay on which the Apache is already installed and we just need to clone the project and configure that it but we're gonna also create subdomain because that's going to be the domain on which react application will be installed but we also need a subdomi and the subdomain will be the IP solid sorry will be the API uh to which this domain will connect so basically the react application will be deployed deployed on this domain and it will make request to for example API dot reactdishsurveys.com so we have to create subdomain um of this domain okay and at the moment if I just open the browser and type API um uh what's the actual domain I just forgot okay reactor I'm going to paste this right here and put API in front of it and hit the enter okay that does not work DNS probe finished so this error indicates that something is wrong with the DNS now I'm going to close the Incognito tabs come in the DNS name servers where we manage our domain and create another a record but in the name I'm going to paste API okay just API and leave the IP address of my VPS IP address so basically I'm indicating that I want to create API subdomain of this domain which I'm managing which will point to the following IP address and I'm going to click add record at the very bottom we should see second uh this for the root domain and we should see somewhere another a record which indicates that this is an API subdoming okay now let's again open incognito and type react Dash surveys.com but let's put API in front of it and hit the enter okay that still doesn't work again it might take few seconds minutes hours depending on many things and whenever this starts working we have API we have domains ready we have the main domain ready we have the API subdomain ready and we need to configure our server so just refresh the page few times and it should start working if that didn't start working after like few minutes uh we need we let's try to add the cname recorded because it didn't start working in my case and sometimes a record doesn't work and uh we just need to try cname record okay so I'm going to close this and come right here and let's change this into cname and I'm going to change this ad symbol into API and the Target in this case will be react surveys.com so the target will be the actual domain and the API will be uh just subdomi in a similar way how here is the www name I did with cname type of record okay so when we do this hit the a record okay so it conflicts with the a record so we basically need to remove this a record you can either have a record or cname record as I mentioned so uh both in this case like both should work but if the a record doesn't work try cname record just delete the a record and scroll up so we have everything filled and click add record and DNS record created successfully okay now let's open again new tab and type API Dash react surveys.com api.reactsurvey.com and hit the enter okay again it might take some time and you just wait some time until the DNS is actually affected in fact if we have a look in the DNS records right here we have the www as I mentioned okay so if we type www.react 342 08:56:10,920 --> 09:09:36,720 Dash surveys.com that I guess works and in the same way API should work okay so this works in the URL we have www okay if we just reload the page to the API it still doesn't work again it might need some time if you have Incognito already open just close the tab and I think I don't have any more Incognito windows open and reopen it and try API react surveys.com after several minutes API reactservice.com started working so we have now main domain reactservice.com and we have subdomain also ready now we can focus on the VPS and work right there set up the application make it working on the following domains and then we can add SSL certificates to have our application securely running on the following domains under SSL okay this is exciting in my opinion so let's close this and now let's go in the posting rage panel let's go in the VPS section and I'm going to grab that SSH comment okay uh if you have already some kind of experience working with SSH you probably have a client for that if you don't have like I recommend to use git Bash this is an excellent terminal in terms of like it has it supports some basic Linux Commons as well and the SSH is also built in gitmash if you have git basically installed locally quite probably and if you're on Windows quite probably you're going to have a git bash if you are on Linux or Mac OS I think your terminal by default supports SSH so there's nothing to do on Windows if you don't have however git bash you can use Powershell Powershell does support SSH okay you can paste the command and hit the end right here and it will ask first of all it will ask us to if we want to proceed and if we want to accept the fingerprint we're going to type yes right here and then proceed but I'm going to close the Powershell because I want to work with the git bash so I'm going to close that open git bash and paste the command and hit the enter okay then I'm going to type a yes right here and then I'm going to provide the password which I gave to the server when I create it okay this should be something very secure password okay and now I am inside the server you know what let me actually uh change some options and increase the text size a little bit here it is Click OK and save here it is I think that this is better okay as I mentioned we already have Apache server running just to make sure that Apache is running you need to type sudo service Apache to status in the enter and if you see active in running in green that's okay you're good to go if you don't have Apache like up and running if you have it installed but not running you need to start it using sudo service Apache to start you can stop the Apache service using sudo service Apache to stop and restart it with sudo service apigee 2 restart that's very basic if you don't have Apache running you need to uninstall it using sudo opt install Apache 2. and you're going to hit the enter however in my case this is already installed so I don't need to do anything what I'm going to do is to update a couple of repositors so I'm going to execute sudo opt git update this will update my server to the latest reposure versions because we're going to install a PHP in MySQL and we just need to make sure that we have the latest repositories from which PHP or MySQL should be correct okay we just need to wait right here few seconds now I'm going to install PHP by executing the following comment sudo apt install HP lib Apache 2 Dash mode PHP uh basically these are two main packages we need to install this is the PHP package and this package is the connector package between Apache 2 and PHP but we're going to also install other PHP extensions because in most cases lateral applications are using those extensions such as PHP PMB string PHP GD for example which is for image processing PHP XML PHP oops XML PHP for example CLI PHP and zip and PHP maybe PHP Json and PHP C URL we might also need PHP Intel and PHP MySQL which is the package which connects PHP and MySQL together so I'm going to hit the enter and agree on this and it's going to take a few seconds until those packages are actually installed okay PHP and its packages were installed now I'm going to clear up the server and I'm gonna install MySQL sudo opt install MySQL Dash server and let's hit the enter we're going to agree on this as soon as the MySQL is installed then we are going to set the MySQL root password and we're going to also run the MySQL secure installation which is a recommended way how you were going to install MySQL on your server okay this is this is important in my opinion so let's clear up everything and first type sudo MySQL and hit the enter and from here we're going to set the root password here I'm going to type alter user and indicate which user I want to alter I want to alter root user for localhost okay and I am going to specify identified uh with identified with mySQL underscore and Native underscore password by and then I'm going to specify right here password I'm going to set the password at the moment to be just one two three four five and six but you should set very secure password uh on your root user so again let's double check alter user I think I have a extra s right here alter user root at localhost identified with mySQL native password by one three whatever hit enter okay so zero rules affected that actually is not a problem so the password for the root user should be changed and I'm going to exceed from here okay now we're going to run sudo MySQL underscore secure underscore installation and hit the enter now we have to provide the root password we just gave this is one two six in my case and now we have a couple of questions in this case MySQL asks if we want to install a validate password plugin component which will validate the strength of our password okay at the moment I'm going to say it's no I don't want that but again on like on your applications if you're building something for production you should probably do this I'm doing this just for the tutorial okay uh in this case the second question is if I want to change the root password I'm going to set this into no I don't want that if you want to remove the anonymous users I'm going to give it a yes if we want to descend low root login remotely this is again very important thing very uh important step for security so you don't want the root access on your MySQL server if you don't really have to make it like available from remote so I'm going to give it no and then if we want to remove the test database and access to it I'm going to type yes and final is if we want to reload privileges table now any changes we made to the user if we want to reload that I'm going to type yes okay now all is done MySQL is actually installed and we can check this by sudo service MySQL status hit the enter we see active and running okay that's good now I'm going to create mySQL database so let's clear up everything and I'm going to type sudo MySQL whenever you type sudo MySQL it's not going to allow any more to access to the MySQL server because previously we didn't have root access that's why sudo MySQL was able to access to the MySQL but now we have to provide password as well so pseudomy SQL Dash PE which indicates that I want to type my password and now my password will be one to six hit enter I'm inside MySQL and I'm going to create new database for my project and I'm going to call this something let's first type create database and let's call this react underscore surveys and I'm going to hit the enter I can hit the enter right here but I'm going to also specify different character set for my database because if someone wants to create surveys in utf-8 what should happen Okay by default it doesn't create the database in UTF so I'm going to specify character uh utf-8 and we have to set actually we need to call character on Charter space set utf-8 and before and we have to specify collate u t f 8 underscore utf-8 mb4 underscore Unicode underscore CI okay I generally have this as a like a gist on my somewhere the nodes so I can copy and paste whenever I need and it just just change the database name so create database the name character set utf-18 before Collide utf-18 before Unicode CI and we're going to hit the enter okay now the database was created now I'm going to exit from here we have MySQL we have created mySQL database in best case I generally generally create a different user for MySQL and then give access on only that specific user to my database okay again if you want like more detailed instructions how generally this should be done I have a separate video how to install Largo application on VPS and I recommend to check this out the link probably will appear in the top right corner of the screen or I'm going to put this also in the video description just have a look and you can find how you can do all all these things in this case I'm just going to connect with the root user to the database I created and that's the react surveys database now I think we can clone the project to clone the project we need to access to the URL GitHub URL so you need to host your project on some git server like GitHub or gitlab or anything else okay so let's type my GitHub and I will have my repository right there let's go on the repositories and here's laravel react survey I'm going to click right here and I'm going to click on this code and I'm going to copy the URL which is with the https and click this copy link now let's go in the project I think by default the hostinger Ubuntu Server doesn't support gits if we just type git command not found so we're going to run sudo apt install and git hit the enter is going to take few seconds until git is installed and whenever this is installed we're going to navigate into VAR www basically you can navigate into any folder you would like and create the project right there but it's a common way and recommended way to do this under bar www okay under inside under VAR www there are only there's only one HTML folder and that HTML folder contains the actual HTML which is rendered when we access at the moment reactsurvey.com which is the default Apache it works welcome page okay so this is it we're going to clone our project right here so git clone I'm going to paste the URL Lara will react survey and let's hit the enter okay now the project was cloned and if I type ls-l key I'm going to see laravel react survey right here now let's navigate into laravel react survey and we're going to run composer install but I think we don't have composer installed as well so we need to install composer - now let's open browser and type git - composer.org 343 09:09:38,098 --> 09:10:09,180 see the enter let's click on download and I'm going to copy The Following part just copy and paste this right here and hit the enter okay it's going to download the composer from the following URL which is mentioned right there and it's going to be available as a composer far file so use it with PHP composer file so at the moment I can already use it if I execute PHP composer bar 344 09:10:09,500 --> 09:18:40,218 and here it is well because we are using the composer with the root user at the moment uh composer will give us a warning that you shouldn't use this with the root user because it might and not it might it will definitely create install the packages under root user permission okay at the moment I don't want to use composer like this I want to make the command globally available again I have composer far available right here but I'm going to make this globally available so whenever I type composer I want to access that so down below we have this sudo move composer far into user local being composer so I'm going to go in the terminal and execute that and whenever this is done I type composer and I have it globally available well I have to agree that I want to use as a root user because I'm logged in as a root user again it will be more complex but we can create additional user log in with that user and clone the project inside that users uh directory and then do the actions right there but but because on This Server we're going to only install one website it's okay to execute this with the root user however if you're going to have multiple websites on your web on your server on your VPS server then it's common practice to create different users for each website and clone the project under that user also create database for that user and then everything what will be available inside this project will only be accessed by that user and no other users will be able to access either file system of any other website or database of another website which is very good and essential security measurement okay but again in this case we have on the webs one website so it's okay to proceed so I'm going to type this right here and the composer is right there now let's execute composer install and hit the enter we have to type yes here and it's going to download and install all the composer packages okay so here's the project already installed and let's copy now Ian dot example into enf and we are going to open now en file with Nano and let's find the database place where we have the databases okay where's the cursor it is right here let's move up here we have the database DB database and let's change DB database into react react underscore surveys I think this is how we called our database and the password will be from one to six again if it's not very clear I'm going to mention one important thing if you are installing multiple websites on the same server it's not good practice to use root user and root user to have access on all the databases because if one website is hacked for some reason the root user will have access on another website as well and if one website is hacked another website will be hacked as well it's common practice to create different user and that different user will have only access to that database react service and if that website is hacked for that user it will not be able to access to another website okay now I'm going to save this I'm going to exit from here and I think I have my project uh almost finished almost set up uh there are a few additional things first because we configured our database we're going to execute migration so PHP Artisan migrate hit enter okay immigrations have been applied this also proves that our application has access to the database otherwise simply it would not be able to run immigrations so we have migrations installed we have like a composer install executed we have to also install node.js and execute npm install and npm run build to build the react application okay this is something also very important now I'm going to open the browser and type nodejs.org let's go on the download section I'm going to scroll down below and find the install node.js via package manager and down below we have these different operating systems I'm going to click this dbn and ubuntu-based distributions and click this node.js binary distributions probably there is a like a shorthand link to this page but this is how generally I go there and if I scroll down below uh we should see here we here we see so for Ubuntu we need to execute the following command which will install the node.js version 18 for Ubuntu so I'm going to copy this part open our server and I'm going to paste this and hit the enter okay node.js is being installed it's going to take a few seconds until it is fully installed not that much and when this is done we're going to execute npm - install and npm run build for react - application foreign okay so here it is installed I'm going to clear up everything and now let's go under uh react but before we go in the react so our laravel application now is intended to be used as an API but if you don't plan to use this as an API you might need to run npm install from the lateral project itself and then you might need to run npm run build as well which will use a white internally to build the assets for your larval application okay let's execute AMPM run and build as well from here it's going to create couple of build files again because we are using our application as an API at the moment this doesn't make any sense we will we will not be able to access those but again I'm just showing how you can do this if you are building in a website and deploying this on your um on your domain okay now let's clear up everything I'm going to navigate into react folder and I'm going to install packages and PM packages so let's execute npm install when this is done uh when this is done we're going to execute npm run build but we are going to also create environment file for production now let's go in the our project and I think we have created.en file so we have this dot enfile which accesses to localhost Port 8000 okay so we're going to create something similar but in this case indicate the production domain so let's open Dot in file under react and I'm going to paste my copied line but instead of localhost Port 8000 and instead of HTTP well let's leave this HTTP at the moment let's leave it because we're going to test this first on HTTP and then install SSL certificate and I'm going to type right here API react dish surveys.com okay let's hit Ctrl o and Ctrl X we quit from here and now let's let's execute npm run build let's hit the enter and here we go so it's going to build our application but we have an error could not resolve t button GSX that comes from dashboard okay something is wrong to the t button js6 let's go in our repository let's go in dashboard js6 and let's have a look where is t button here is t button okay white is not resolved here is the t button okay let's execute this npm run build from here from the local installation npm run build hit the enter 345 09:18:41,460 --> 09:18:45,378 password is building for production 346 09:18:46,200 --> 09:18:49,520 it needs some time 347 09:18:53,758 --> 09:19:01,640 okay it was able to build successfully which node.js version do I have a node 348 09:19:02,160 --> 09:19:35,182 16. so I have version 16. I guess this is not a problem uh that I have 16 and on server there is 18. there's there's some kind of problem so let's have a look with which branch I am I'm on Main brain so hit push origin do I have something to be pushed origin Main let's hit the enter everything is up to date okay something is wrong let's try to - execute this once again but I think it - will not work 349 09:19:35,460 --> 09:19:46,096 okay could not resolve components core t button j6 from Source views dashboard j6 350 09:19:48,780 --> 09:19:56,780 that's strange so let's type if theories components core 351 09:19:57,300 --> 09:20:06,596 t button GSX do we have that under source 352 09:20:07,620 --> 09:21:17,756 there's components then under Source components there is core in under Source components core there is t button gs6 but it wasn't able to resolve that from Source views dashboard js6 that's range okay if we have a look if we navigate into source and have a look so we have right here views and components now if I just type files under views there must be dashboard okay here's the dashboard now let's print what is the content of the dashboard.j6 if we scroll up we should see right here the path somewhere to t button in QC so we just go One Directory back from the views navigate into components core tip button j6 353 09:21:18,300 --> 09:24:29,180 this is very very strange t button maybe the problem is in uppercase lowercase components core t button on Windows generally application lowercase naming of the components is okay but on Linux this is not okay so maybe the problem is in lowercase and uppercase naming so if I navigate into components in core and have a look exactly that is the problem so here we have t button with the lowercase but actually we're trying to import this with the uppercase so I just need to open my project and find t button with the lowercase let's actually match the case and I think it is never used like in lower case we don't ever use that so now I need to go into core t button that's actually something which looks uppercase in my case this is even more strange like this looks like uppercase right here but on the server it is lowercase if we check this on the git repository I just don't want to spend more time on this part it's very strange and very interesting case so if we go in the Source components core we see t button with the lowercase okay this is the problem well What if I come right here I'm going to copy everything this is generally how I used to do I used to fix these problems I'm going to copy everything from this t button and I'm going to actually delete that okay I deleted that then I opened the version control system and I am going to actually commit that deletion I have other changes as well but I'm going to leave them at the moment I'm just commit these change and call this remove t button Okay click commit that was changed now let's bring up the terminal hit push origin Main that is pushed okay now I'm gonna recreate this file under core but I'm going to call these with uppercase B in this case pattern j s x and I'm going to paste all my copied code so now I save this and again I am going to make a commit add T uppercase button click on it now let's push this and now let's check the server if I just reload the page I see now in uppercase B okay and I'm going to also comment these changes which I recently made a small changes to dashboard 354 09:24:29,580 --> 09:24:33,256 let's push those changes 355 09:24:33,900 --> 09:24:37,520 and I'm going to open the server 356 09:24:38,880 --> 09:24:58,880 I'm going to navigate back into my project and run gitbull that's going to pull the latest changes into the folder and now if I navigate into react folder I'm going to execute npm run build and let's wait for a few seconds 357 09:25:01,560 --> 09:26:18,740 okay so now react build was successfully completed Okay small additional things what you should probably do is to create a storage link when to execute PHP Artisan storage column link oops storage column link I think this is how we should execute that it created the storage link and let's change the permissions of the storage if we don't want to have basically some kind of permission issues so we're going to execute sudo CH mode 775 and let's specify here the storage folder so I want to change the permissions of the storage folder entirely to the following now we are going to create virtual hosts so we have the project like fully ready now let's create virtual hosts we're navigating to Etc apache2 sites available okay this is the folder inside which we are going to create virtual uh host config file and I'm going to execute Nano let's create the let's give it the same name as whatever is our domain like react 358 09:26:19,340 --> 09:26:52,096 surveys.com.com make sure to always give.com extension to your config file otherwise it will not work and right here we're gonna put uh like the virtual house template so let me actually exit from here because we have a zero zero zero default config file and I'm going to actually open that zero zero zero default and this is it okay this is how it looks like and we can actually use that but I have feeling that this is not gonna uh work exactly as as it should work 359 09:26:52,436 --> 09:29:12,720 so let's actually create this new file where we are actually creating and I'm going to copy and paste the virtual host and I'm going to put the link to this file also in the video description okay and we need to adjust few things the server name that's going to be the name uh of our of our domain so we are editing right now reactsurveys.com file so the domain should be the server name will be the domain and that should be react dish surveys.com okay the server admin should be the email of the admin who is going to manage the server at the moment we don't plan any kind of like heavy management so I'm going to leave this as it is I'm going to change the document root which should be the path to our project to our PHP executable file the entry script more correctly to say entry script that should be react-ish surveys.com public okay this is the place where the index PHP locates which should be executed every time when you access to the website or or my mistake so we are right now editing the reactservice.com that should be react website and API reactsurvey.com that should be the laravel website so the path should be basically react slash dist because whenever you build the project in react that's going to be under this folder okay so this is how we should do and then let's change this into react surveys.com react slash react we can also specify these right here but let's leave it as this if we change the we can change the error and access logs if we want but I'm not going to change that I'm going to leave this and I'm going to save using Ctrl or control X and actually I'm going to copy these a react surveys and call this API dot react Dash surveys.com.conf 360 09:29:13,200 --> 09:32:56,159 okay now let's open API react surveys and we're going to change the server name which should be Now API Dot reactsurvey.com and the document root will be in this case public okay reactservice.com this is this is this is the path this is the path of index PHP okay and right here we need to specify just reactservice.com so I'm going to hit Ctrl o Ctrl X to save and quit and we have to enable those two configuration files so we have Now API reactservice.com and reactsurvey.com so we're going to run sudo A2 in site which means that we're going to enable the site API reactsurveys.com so we're going to enable that and we're going to also enable react surveys reactsurveys.com so we enabled that now we need to reload Apache sudo service Apache to reload okay so Apache was reload and one additional thing which we have done is to enable rewrite mode on Apache so we're going to execute A2 in mode rewrite hit the enter the rewrite mode was enabled but whenever you enable rewrite mode you have to restart Apache so we're going to execute sudo service Apache Apache to restart hit the enter okay Apache was restarted and now it's time for Magic or it's time for pack fixing maybe we did everything but we haven't tested anything so far while we're deploying so we're going to type reactsurvey.com and let's have a look okay so we see steel Apaches welcome page to have like in coding two tabs open no we don't have so again let's open reactsurvey.com we see Apache welcome page which means that our virtual hosts actually not work as expected reactservice.com let's go in the terminal and now let's debug our problem okay so whenever you create a file and then configuration file and then enable that uh it's going to move into sites enable folder okay it's going to create symbolic link into sites enabled so actually if we type ls-l-a and we go One Directory back and go inside sites enabled right here we should see those two files as a symbolic links let's actually that's just an information okay if they are not right here available then this is the this might be the reason why it's not working but if it's right there then let's open it and debug it okay what problems we have the server name is reactsurveys.com okay I think this is exactly how it should be reactsurveys.com okay the path is reactsurvey.com reactist reactservice.com react okay is this directory correct now let's check this everything looks good now let's go under VAR www.react [Music] 361 09:32:56,160 --> 09:33:21,240 oops let's have a look okay I think this is the problem okay this is the problem so our path is incorrect because we copied this from GitHub and it gave a different name okay we should change this and name it whatever is our domain so move laravel react survey react surveys.com 362 09:33:22,020 --> 09:35:34,756 let's hit the enter now right here we have reactsurvey.com okay now path is accurate and if I reload now it still doesn't work now let's try by the way API react surveys.com hit the enter wait for a few seconds okay we have some kind of problem okay this is the problem this is coming from the laravel it looks like our second sub domain our second installation second virtual host actually works so we are inside laravel at the moment but we have the permission issues and it comes from the storage so if we now just change CH mode 777 into storage uh well it should be inside the project folder storage hit the enter okay the permissions was completely changed into inside the storage and if I just reload the page let's have a look storage logs laravel okay we should change this recursively this is my mistake so CH mode uh we should probably specify Dash uppercase R right here 777 now it was changed recursively and if I reload the page this is the error which I expected no application encryption key has been specified and that's okay go inside reactservice.com and execute PHP Artisan key column generate dish station PSI okay he successfully reload the page and we see a lot of application up and running okay so API is ready but what's wrong with the react application probably the path is not correct let's navigate into react I think it might call build or it's called actually dist so under react there's this okay now let's have a look what information is inside dist HTML okay 363 09:35:35,820 --> 09:37:31,160 why it doesn't work so probably the virtual host file does not read index.html and it only reads PHP not sure but I think again if we have a look so inside this we have index HTML so the path looks actually correct so VAR www.reactservice.com react and dist now let's open Etc apache2 sites available sites available and the actual virtual host should be react surveys.com and again let's check it so we have for www.rixervice.com react test okay the path looks accurate and down below we have this directory uh hello override although we need this hello override maybe that's that is for the PHP okay I'm actually debugging a few things right now so I'm going to comment this out okay and let's actually put this into double quotations because I know double quotations actually work so I'm going to put this like like this in the domain react surveys.com is actually accurate so I'm going to save this okay and execute sudo service Apache to reload so whenever you change your virtual host file you need to execute these now let's have a look okay it doesn't seem to be working well actually I want to debug this problem so I'm gonna type Apache uh virtual host on index HTML because I have a feeling that this might be the reason 364 09:37:32,096 --> 09:37:52,160 okay so we have document rule document name actually this comes from the official documentation of Apache which generally has much more information than I need so I'm gonna find something probably from stack overflow let's accept all the cookies 365 09:37:52,500 --> 09:38:23,000 okay we probably need to set the directory index that is good that's good point so let's grab that and open our react service file and let's create here oops okay hold on I mistakenly hit the Ctrl Z which is something which I shouldn't have done 366 09:38:23,400 --> 09:38:27,740 okay I'm going to paste this directory index 367 09:38:33,416 --> 09:39:14,820 and let's save this and reload Apache and have a look in the browser where is it it's right here okay it still doesn't work which is strange uh let's open in not incognito okay inside normal browser it even thinks that this is a it has cache basically to say natural so let's close all the tabs again from the incognito and reopen it now we still have these reactsurveys.com 368 09:39:16,436 --> 09:39:27,500 um Apache well I I have a feeling that I should receive actually not found if 369 09:39:27,776 --> 09:40:20,220 okay I'm gonna go now inside bar www.html okay and right here we have this index.html which I'm going to delete let's go One Directory back in rm-rf HTML folder okay I completely removed that now if I reload the page I see not found okay that's fine but it's not found should not be displayed because we have these domain react service domain mapped to a virtual host okay again if we go inside Etc Apache to sites available here we have here we have this react surveys.com we edit reactsurveys.com 370 09:40:24,000 --> 09:41:05,960 let's remove this Nano named everything actually everything looks correct okay Apache two virtual post on index HTML not working okay so Google is our best friend recently actually chat GPT became one of my best friends maybe we can ask Chad GPD about that but let's see these pages 371 09:41:07,560 --> 09:41:24,020 okay um I'm basically looking for a short end size answer I don't want to spend too much time on debugging right here okay it looks like 372 09:41:24,540 --> 09:41:28,160 I can't have that 373 09:41:33,540 --> 09:41:44,180 Apache Apache virtual host on index.html not working 374 09:41:47,460 --> 09:41:57,200 okay this looks like no this is not actually this is something I have already checked 375 09:41:58,800 --> 09:42:02,840 okay let's have a look here 376 09:42:06,180 --> 09:43:07,276 okay this is I think what I want this is I think what I want to see if there's an accepted answer uh do you have AC access in your somewhere alone override all okay do we have hello override all I think we have that but I have a feeling that this part not deny from all in yellow from more but this part is exactly what I need so I'm going to copy this I have done this previously multiple times just I can't remember these type of things by heart so that's why I have to Google if I do this daily of course I can remember but I don't do this daily so I'm going to paste this and let's delete this part 377 09:43:10,980 --> 09:43:14,060 like this 378 09:43:16,860 --> 09:43:27,916 and then we have to change the directory to be to be something which is reading here 379 09:43:31,436 --> 09:43:48,320 okay maybe we don't even need the directory index or maybe we need it but the index HTML should be the first one okay anyway let's save this as it is and execute sudo service 380 09:43:49,436 --> 09:44:10,820 Apache to reload okay it was Reloaded now let's reload here okay we still have not found this is very strange this is very strange it looks like it doesn't actually care my virtual host 381 09:44:13,380 --> 09:44:18,436 it actually does not cure my virtual host 382 09:44:25,740 --> 09:44:30,680 okay let's remove this directory index 383 09:44:33,800 --> 09:45:09,380 okay I'm gonna find out where is the problem where is the actual problem okay so I'm gonna now save this again reload the server in refresh the page okay now I'm going to create index PHP maybe the problem is inside the index.html not sure let's try a different approach on the backing okay or www uh react surveys under react folder okay here I have these inside these I'm going to create 384 09:45:09,740 --> 09:45:17,960 uh CD test I'm going to create PHP file Nano 385 09:45:18,360 --> 09:45:22,756 um index dot PHP 386 09:45:28,080 --> 09:45:55,436 hello okay I save this and exit now if I reload the page I don't see Hello however I should see because I have created that okay now let's open again Etc Apache 2 sites available react surveys.com 387 09:46:01,320 --> 09:46:06,200 okay let's comment out these parts 388 09:46:09,840 --> 09:46:20,240 let's open now second virtual host and what do we have here so we have 389 09:46:20,580 --> 09:46:50,700 so we have to uh our second virtual host should look like exactly this okay as you see so we have a low override all so let's exit from here propane react and maybe we need to activate a low override not this one let's all activate hello override all Okay so 390 09:46:51,120 --> 09:47:02,840 oops let's save this and we have to reload Apache so the service I cheat to reload 391 09:47:03,480 --> 09:47:35,120 okay now let's have a look again not working this is getting annoying to be honest now I'm going to map this into the same directory we are API is mapped that should work right so let's map this into like public and then here we need this 392 09:47:42,320 --> 09:48:01,580 reload and refresh still not working however API react surveys it does work that opens larval come on 393 09:48:05,276 --> 09:48:20,160 so have things like the same things inside here and inside the API so now let's open API 394 09:48:23,096 --> 09:48:40,640 like we have the exact same things right the only difference is that we have we didn't have double quotations well let me actually copy this part completely and exit from here 395 09:48:41,340 --> 09:48:45,436 and I'm going to delete everything okay 396 09:48:45,776 --> 09:48:51,320 how can I delete the entire line 397 09:49:00,960 --> 09:49:08,240 okay here I pasted and I'm going to just remove this API 398 09:49:10,620 --> 09:49:46,820 now let's reload the page okay it's not working something is wrong with that and I hope it just was Cash no it's not Gish okay I think I know the reason for for this I think I know that the problem is probably in the main domain so if we actually navigate into uh sites available folder and have a look let's open zero zero zero 399 09:49:50,640 --> 09:49:53,596 here 400 09:49:55,256 --> 09:49:59,060 no this is just an example 401 09:50:02,096 --> 09:50:06,436 this is just an example 402 09:50:10,256 --> 09:50:21,960 changing the virtual host doesn't seem to be working okay let's exit from here and let's go into sites enabled 403 09:50:24,180 --> 09:50:59,660 here we have zero zero zero default which I am going to disable so sudo A2 this site zero zero zero so I want to disable the default one sudo service Apache to reload and reload Apache now let's clear up and let's open uh react surveys it's called that was the reason the default one was the default one basically spent my like 15 minutes 404 09:51:00,360 --> 09:51:05,720 okay let's now edit 405 09:51:06,300 --> 09:52:50,820 Etc Apache 2 like the most amazing things that generally that's why I love love programming I know that I can find the answer okay so it it might take 5 minutes 15 minutes 20 minutes but finally I will find the answer and this is just uh this is just how I approach the things so don't give up and you're gonna always find the answers on your problems okay just don't give up maybe you you can have a break like one minute five minutes one hour one day break but then when you go back you should continue and then finally you can find the answer sites sites available um no I am editing sites available sometimes I make such such stupid mistakes or mechanical mistakes okay I need to open uh react surveys.com and I'm going to modify now document root it should be react slash dist let's quit from here and sudo service Apache 2 by G2 reload okay now let's open reactsurvey.com this still shows hostinger let's open incognito and look at this look at this so we have react application up and running now let's try to log in I think we won't be able to log in because we don't have any account let's try to sign up okay so write example.com 406 09:52:51,900 --> 09:53:22,320 now let's pay attention where the request is sent click and have a look so the request is made on HTTP API right surveys.com perfect CD VAR www .react go inside react folder and open envo 407 09:53:27,180 --> 09:53:57,200 okay I have a typo here that should be react surveys okay and we need to rebuild actually npm run build this is what we're going to execute and whenever this is done we are going to reopen our page application come on finish it okay it's done so I will load the page 408 09:53:58,080 --> 09:54:57,916 okay that's another problem by the way which we have to fix so I am on the login that works fine if I just reload the page I get not found okay that's not a problem to fix um actually I can fix this right now um I know how to fix that Apache I can't remember it by heart but I know that it's that should be um everything basically should be redirected on the index HTML so Apache to redirect on index HTML okay let's have a look we should have a quick solution I think this should work they are like slightly different variations of that so I'm gonna now open Etc Apache to uh sites available react and I am going to 409 09:54:58,800 --> 09:55:03,320 paste this here 410 09:55:12,240 --> 09:55:27,300 and sudo service Apache 2 reload and remove the page that didn't work strange 411 09:55:27,840 --> 09:55:54,060 generally I go with this approach except that I don't put this in the URL but I think that will work as well Maybe the place should be inside the directory or we can even create the HD access so let's try put to put this inside the directory 412 09:55:56,700 --> 09:56:01,340 if I'm going to put this here 413 09:56:02,880 --> 09:56:42,916 paste I can format this or I'm going to leave it let's move up and comment out this and reload Apache and refresh the page okay I didn't configure it correctly okay when I hurry up I have problems okay what I need to do okay the best one will be to put this in the index in the uh HD access okay I know for sure that it's gonna work 414 09:56:43,980 --> 09:57:34,680 so we can create htaccess we cannot actually create HD access the HD access should be creating inside the dist folder and the dist folder is something which is deleted and recreated every time you execute it so whenever we execute npm run build it's going to delete this folder and recreate that so if we have to create HD access file we're going to put the content inside this folder and that's not actually correct so we should put this maybe here okay let's actually find like the best answer just to down tools Apache 2 redirect index HTML in there are 12 hosts 415 09:57:39,596 --> 09:57:41,960 okay 416 09:57:43,560 --> 09:57:59,540 in the apache2 conf okay I don't want to make some changes in Apache to conf I want to do this in the virtual host so we have the we write engine on now this is not what I want 417 09:58:00,300 --> 09:58:12,180 this is not what I want I want redirect everything on index HTML 418 09:58:14,640 --> 09:58:22,340 everything on index.html this might pick it or this might be it 419 09:58:22,620 --> 09:58:28,700 change hello right 9 into all 420 09:58:29,460 --> 09:58:32,720 I don't want to 421 09:58:33,180 --> 09:58:38,240 change the HD access or create HD access 422 09:58:49,500 --> 09:58:51,980 okay 423 09:58:52,256 --> 09:58:55,880 we can try that 424 09:58:58,500 --> 09:59:01,520 or maybe that 425 09:59:02,220 --> 09:59:05,900 let's put this in the 426 09:59:08,520 --> 09:59:21,140 yeah I'm sure putting this in the HD access will do the job but I don't want to create an HD access I want to do this in the virtual host 427 09:59:34,256 --> 09:59:39,256 okay this is not this is not hap 428 09:59:44,160 --> 09:59:53,000 this might beat we write engine on okay now this is not also what I expect 429 09:59:56,820 --> 10:00:42,860 okay let me actually try this but I'm going to put this inside the directory in this case so let's put this under hello override rewrite engine on Rice condition request Yuri and anything that does not equal to index.html let's redirect it into index HTML I think that should do it let's try I'm gonna reload the server and let's have a look okay so we are actually redirected to the index HTML which is not what I want come on 430 10:00:46,560 --> 10:00:57,080 okay another version like which what I saw was this 431 10:00:58,200 --> 10:01:01,276 okay let's search for 432 10:01:01,860 --> 10:01:50,300 um let's search for hold on do we have such thing in the public where's the public we have HD access okay so we have something similar here it's much more complex but we have something similar here okay so this is it so it anything that is not request file name or request uh file name directory so if it's not a directory and if it's on the file name redirect to index PHP so basically I need these okay but I need it for index.html Okay so I'm open opening again virtual host file 433 10:01:50,640 --> 10:02:20,060 and I am going to change this so I'm going to actually well let's uh let's leave the right engine on and I'm going to delete the rest here and paste so we enable rewrite engine and anything this is not a file name and anything this is not a directory it should be redirected to index that should be HTML 434 10:02:20,700 --> 10:02:53,060 let's save exit reload Apache and trade again okay let's remove this index okay now let's have a look okay we have an error internal server error and we need to have a look in the Apache tail bar log Apache to airlock 435 10:02:57,776 --> 10:03:45,560 tail let's let's have an output and if we just reload the page okay request exactly the limit of turn internal redirects due to probable configuration error limit internal recursion to increase the limit okay I'm going to now search for Apache to Spa virtual host config now let's see what it gives me I'm obviously creating a single page application right here it is my react app 436 10:03:47,096 --> 10:03:56,900 okay virtual host directory index document root this is Engineers but we want Apache 437 10:04:05,700 --> 10:04:11,720 what am I missing like location is is this where I'm missing 438 10:04:15,500 --> 10:04:29,720 okay I don't want this to be under subfolder basically I want this to be on root domain so let's go back the sensor is used useless for me 439 10:04:32,096 --> 10:04:43,040 okay they start installing from Apache you know what I am going okay if this is not going to help I'm going to use chat GPT 440 10:04:54,960 --> 10:05:06,200 this doesn't do anything at all okay let's try to use chat GPT 441 10:05:20,700 --> 10:05:46,800 okay um I want to create virtual host for react application my application should be deployed on production um on primary domain 442 10:05:49,320 --> 10:06:00,620 I basically didn't even ask anything uh and it gives me instructions okay I know this 443 10:06:05,900 --> 10:06:22,400 and here's the virtual host we this is what I'm interesting okay document root should be your app directory options indexes follow Sim links hello all right all 444 10:06:25,680 --> 10:06:31,160 and this is how I need to enable my virtual host file 445 10:06:35,000 --> 10:06:49,820 that should this is not actually bad this is very good so I'm going to copy this part and add into my code let's open now the virtual host file 446 10:06:55,020 --> 10:07:08,660 actually I'm going to use veeam because I don't like Nano so veeam a TC is leaving available yes it is 447 10:07:09,180 --> 10:07:27,020 okay veeam Etc Apache 2 sites available reacts okay now I'm using V which is much cooler 448 10:07:33,060 --> 10:07:38,660 okay I think I need to delete this art 449 10:07:39,840 --> 10:07:47,416 and I'm going to paste these okay and we don't need these 450 10:07:48,776 --> 10:07:53,776 okay that's not bad now let's reload 451 10:07:54,720 --> 10:07:58,580 now let's reload 452 10:08:00,000 --> 10:08:03,500 and have a look 453 10:08:04,560 --> 10:08:14,720 now I had not found because I don't redirect anything to index HTML now let's open again chargpt and ask 454 10:08:16,220 --> 10:08:32,096 I won't react well I am using react rooting as well can you update config accordingly 455 10:08:34,500 --> 10:08:53,840 okay now I I assume that it's going to give me what I want exactly because I just gave it a like high level idea I want everything to be redirected to index.html so that it works properly 456 10:08:57,120 --> 10:09:08,416 I guess the answer is the same now here it comes we write the engine we write base okay 457 10:09:09,240 --> 10:09:14,900 okay okay so let's copy this 458 10:09:18,300 --> 10:09:22,580 this is this is cool 459 10:09:28,740 --> 10:09:33,620 where is my cursor sometimes I lost the cursor 460 10:09:36,360 --> 10:09:47,960 okay now let's see so I think we have everything is Chad GPD recommended us 461 10:09:49,080 --> 10:10:03,320 and we just need to save and reload Apache now we have an error today make some kind of mistake 462 10:10:08,776 --> 10:10:14,416 okay we need to have a look what's the actual error 463 10:10:17,220 --> 10:10:21,436 it's getting annoying a little bit 464 10:10:33,180 --> 10:10:35,480 foreign 465 10:10:44,660 --> 10:10:48,380 failed for Apache 466 10:10:50,096 --> 10:10:58,580 we write bases and only valid in a paired directory okay this is the problem 467 10:11:01,500 --> 10:11:36,800 let's open Virtual host again I I swear I'm doing this like uh probably 100th time but every time I do this I I forget certain things so let's specify right here full path react and dist I want this to work inside reactist now let me actually copy this rewrite engine and put this why I don't see the cursor come on 468 10:11:39,540 --> 10:11:44,180 okay and I'm going to 469 10:11:46,560 --> 10:11:49,276 delete 470 10:11:51,240 --> 10:12:02,120 everything okay is everything okay right here looks good now let's reload Apache 471 10:12:07,256 --> 10:12:41,776 okay here here it is okay 101 times but I swear if I do this tutorial like after one month I forgot and I will spend the same amount of time but at least I think JoJo helped us yeah you didn't put this on inside the directory it did put it in a wrong place but it was kind of hint for me okay now let's try to sign up 472 10:12:42,480 --> 10:12:45,020 foreign 473 10:12:54,020 --> 10:13:22,936 we signed up successfully so front-end Works API works this is actually awesome let's create test survey test let's upload let's see if image uploading actually works so we create test let's say one question test question and we have to choose the date 474 10:13:23,880 --> 10:13:35,300 and click save okay here's the error the error is about the permissions 475 10:13:37,560 --> 10:13:45,320 okay we weren't able uh to put the file in under images 476 10:13:49,680 --> 10:13:55,936 okay we need to when to fix that as well 477 10:13:56,580 --> 10:14:21,860 uh we don't need GPT we need the server let's go back and I think it's trying to put that under storage images right so and I think we change the permissions of this storage yeah everything is changed and there's also symbolic link from Storage 478 10:14:22,256 --> 10:14:25,700 up public 479 10:14:28,500 --> 10:14:52,860 I think so so if we go in the public there is images right here and that images is I think what the application uses at the moment so we just need to change CH mode recursively our case are 777 480 10:14:53,340 --> 10:14:55,880 images 481 10:14:57,300 --> 10:16:58,276 okay I changed the permission of images and I try to resubmit the form and Survey was created okay that's perfect now the last thing is to install SSL certificates to install the install certificates first we have to install some of the packet packages so I'm gonna run sudo opt install Search bot search but we're going to install Python 3 bot Apache and I think yeah that's all this is all what we need I'm going to hit the enter this is going to take a few seconds until this is installed and then we're going to execute sudo searchbot okay so this is done let's execute sudo third part and let's specify this Dash Apache okay I'm going to hit the enter okay Enter email address used for Argent renewal and security notices I'm going to enter my email address right here okay now we're going to read these terms which is written in the PDF so you can actually copy these open and read that and then you have to agree this or not okay I'm going to type y because I agree all the terms would you be willing once your first certificate is successfully issued to share your email address with the electron okay I don't want my ammo to be shared account registered and the third particularly found that we are using two domains react surveys in the API react surveys okay and we have to select the appropriate number separated by commas and or spaces or leave input blank to select all inputs shown so excuse me so I'm going to hit the enter 482 10:16:58,560 --> 10:17:48,256 okay so the script was finished and pay attention now it gave us the following output it deployed the certificates and successfully deployed certificate for reactsurveys.com and successful deployed certificate for aparic surveys.com okay however it created different Apache config files for the SSL version like Le sso.com and right here we have this API react service.com less excel.com okay and it gave us also this red message that it added also redirect from HTTP into https before we check this in the browser I want to navigate into Etc Apache to 483 10:17:49,320 --> 10:18:08,756 sites available and let's have a look so now we have two additional files API reactservice.com with let's encrypt version and react service that come with a less encrypt version now I'm going to open first reactservice.com 484 10:18:09,860 --> 10:18:37,820 but without less encrypt okay so here let's see let's have a look what happened so down below it added the following right condition so if the server names reactsurvey.com it is redirecting it to the https version of the URL basically which is received and now let's have a look at the let's encrypt version 485 10:18:38,640 --> 10:19:10,700 here it is so the virtual host Port was changed into 443 and right here everything stays the same except that down below it's using the SSL certificate files and key file and it's including the following configuration option as well okay so this is what happened and I think Apache was also reloaded and if we check now in the browser if I just reload the page 486 10:19:10,980 --> 10:19:15,436 um okay there's some kind of error 487 10:19:18,240 --> 10:19:28,400 okay let's actually close all and reopening Incognito because again it might be cash 488 10:19:30,180 --> 10:21:16,340 well this is not cash but the redirect doesn't work probably because we have to reload Apache so sudo service Apache to reload now let's see a does not actually work it doesn't actually work and it's it's bad that I didn't read the actual output okay let's check again in cognito because I have a feeling that like the redirect doesn't seem to working but it should be implemented correctly right so if we oh I think I know why it might not be working okay let's check API first okay on API the redirect actually works and we are under SSL however if we go in and edit Etc apache2 sites available react and that should be without https so here we have the rewrite condition but actually there is additional rewrite rule um above so basically uh let's encrypt could not detect that we we had this and this overrides I think this part so in this case because if the request comes without SSL without https we need to redirect it to the with the SSL version so I think we don't need to do here anything so we just need to oops 489 10:21:16,680 --> 10:21:58,040 we can remove that completely okay I'm going to save and quit and reload pseudo service Apache 2 reload and now let's reload the page and now we see not found a game and that probably happens because that rewrite conditioning rewrite rule doesn't seem to be working so now let's copy this oops I deleted something incorrectly so I'm going to quit and have a look 490 10:21:58,800 --> 10:22:02,660 now let's paste this right here 491 10:22:04,140 --> 10:22:13,340 and delete and quit and reload and reload and again doesn't work 492 10:22:14,400 --> 10:22:22,040 it does not work as expected come on 493 10:22:23,460 --> 10:22:32,040 so what are we doing a theory right condition if the server name is reactsurveys.com 494 10:22:32,520 --> 10:22:35,960 we've redirected 495 10:22:37,980 --> 10:22:48,200 like it looks it looks good it looks correct so I copy that let's move up 496 10:22:48,960 --> 10:23:25,436 put this here as well not sure if it is necessary but we just want to redirect okay we don't want to proceed or do anything and reload Apache and refresh not working I'm going to open chat GPT again now and ask redirect known um oh let's type like this redirect http requests to https in Apache 497 10:23:26,340 --> 10:23:29,900 virtual host 498 10:23:36,180 --> 10:23:40,580 we will get some kind of answer I'm sure 499 10:23:40,980 --> 10:24:19,400 okay what's encrypt didn't do as it was necessary that was that is an excellent idea so we just take slash under Port 80 and redirect to the follow that's amazing idea that that is awesome so we come right here and basically let's let me actually copy this okay so we'll listen to Port 80 so we are in in the known https request so we basically don't need all these 500 10:24:21,360 --> 10:24:25,340 okay none of them is necessary 501 10:24:26,096 --> 10:24:33,680 and just um I didn't paste what I wanted 502 10:24:36,300 --> 10:24:38,840 okay 503 10:24:40,200 --> 10:25:14,540 oops no that's good and paste it here okay so I take anything that comes under this virtual host and redirect into react slash surveys.com this is awesome reload Apache and have a look oops I think I am missing an extra slash somewhere let's redirect this into 504 10:25:24,120 --> 10:25:40,756 beam is complex actually much more complex than Nano but much more powerful as well okay so I'm going to open react surveys.com hit the enter 505 10:25:41,540 --> 10:26:42,620 and and end and something is wrong certificate is not valid and I think this is because of the date in my computer my date for some reason every time I restart my computer is wrong every time it goes into two hours uh sorry four hours ahead actually it's at 2 am at the moment but it shows me 10 p.m and I have no idea why it does this and I didn't spend enough time to actually find this out so what I'm gonna do is just manually change the time to be correct and it's going to be two six and click change okay this is actually the correct time locally and I reload the clock is a head no it's not a head it's 6 February actually 506 10:26:48,660 --> 10:26:56,180 wait hold on now it should not be PM it should be am so here definitely 507 10:26:57,480 --> 10:27:00,500 to 2 am 508 10:27:01,220 --> 10:27:04,580 oh my God 509 10:27:04,860 --> 10:28:23,120 what am I doing just image okay I'm laughing at the moment because imagine I was actually deploying my larval react project on Virtual private server and I ended up changing date on my computer ridiculous but that's true that's true how they are connected to each other okay changing how deploying lateral projects on Virtual private server is connected to changing date in your computer okay now we have the application deployed under SSL certificate it's secure the only thing we need to do is I said this probably a thousand times the only thing what we need to do the only thing what we need to do the only thing we're trying to do but now I think really the only thing what we need to do is to go in the react and just edit the.en and specify https right here so now the react application needs to connect to the https of the server okay 510 10:28:24,776 --> 10:28:49,160 we don't need to restart Apache or anything but we need to execute npm run and build so when this is done we are going to have final application under SSL up and running it took much more time than expected because we spend some time on stupid things 511 10:28:50,096 --> 10:30:04,096 but this is how it is now let me try to log in the request was made under SSL under https everything worked we are in the system this is our application thanks for watching please hit the like button and subscribe if you are not yet check my premium course as well building a full stack e-commerce application with a laravel vue.js Talon CSS alpine.js it's going to be available on the codeholic.com I have a discount I don't know how long I will leave this discount but you can grab the whole course which is about 23 hours content 140 videos like having a fully functional project and this is something which you can definitely put in your portfolio and just be proud of it so just have a look have an overview of the course have a look at the um like curriculum and if you find it interesting maybe you can enroll it and I will help you as much as I can to complete this course okay 441494

Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.