I Built Full Stack Application with Laravel, Vue 3 and Tailwindcss

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone my name is zura and i'm the co-colleague on this channel i do coding tutorials and challenges as well as some tips tricks and advices if that sounds interesting to you consider subscribing i have been working on this project for a very long time and i'm so excited that i want to show you demo immediately [Music] let's open the domain your surveys.xyz it's going to redirect you to the login page let's click register for free and fill up this form as soon as you fill up the form click the sign up button you will be registered and redirected to the dashboard page dashboard is an overview and gives you information about latest survey total surveys total answers and latest answers let's go on the surveys page so far we don't have any service so let's create a new one we can choose image on a survey or leave it empty it's optional we need to specify title and description we can set the expired date whatever we want in the future and we can mark the survey active or leave it draft next we need to add questions let me add a couple of questions we have five types of questions text select radio checkbox and text area select radio and checkbox type questions need additional options you can add as many options as you want here i have added seven questions and let's have a look at all of them some of them is checkbox some of them is radio i have also text field and text area questions now let's submit the form as soon as you submit the form you get the notification that the survey was successfully created we can have a look that the questions do exist right there so all seven questions checkboxes radios with their all options we defined is right there okay let's click this view public link that's going to open the survey from which we can take and complete that that's a public url meaning that you don't need to be authorized to complete that survey let's go in the survey listing and right here we see one survey we have this open button right here as well and the delete survey button let's go on the dashboard and now we see that the latest survey is there total surveys we don't have any answers so far now let me actually take that survey complete that to make an answer i'm going to choose some options right here specify some text in text area and text field as well and hit the submit button as soon as we submit the survey we get this nice notification we can submit another survey if we want now let's go back and reload the page and now we see we have total answers one on the right side we also see the latest answer let's actually go to the service page right now we only have one survey down below we see the pagination but it's not going to work because we have only one i'm going to actually import many surveys and have a look how they look like and we're going to have a look at the pagination as well here i imported database with 12 surveys and answers as well and this is how it looks let's go on the surveys page we see all the surveys with their images it looks nice we have pagination implemented let's go on the second page right here we have only two records this looks awesome and i forgot to mention but everything absolutely everything is responsive and mobile and tablet friendly if we expand this now this is the tablet view we always see those cards divided like this spread like this if we even resize on the dashboard size this is how our our cards look like okay this works up to very small screen size let's go on the surveys page this is slightly buggy so we're gonna fix that but look at this so 30 pixel okay and that's going to work perfectly here we have all those cars if we expand it in tablet view we see two cards next to each other if we go inside the card all the questions also are let's click on that all the questions also are responsive i think we need to work slightly on the header in terms of responsiveness whenever you click that view public link if the survey is not active or its expired date has already been passed then you're going to see not found so right now the server is not active and we see not found this page is ugly i know but the idea is that you should not be able to see the survey if it's not active okay as soon as i activate that survey and save this now let's close this and go up and view public link and now we see that survey or even if i change that expired date into past i actually technically cannot change this in the past but if the expiry date passes then also we're gonna see not found right here i hope you like the demo we're gonna build everything from scratch we're gonna build laravel rest api with authentication then frontend with the talon css and vue.js and connect them together so the project the process is not split into back end or front end the process is basically combined sometimes i make some changes in the backend then on the front end so this is a building a full stack application and finally we're gonna deploy this on a production ready environment as a choice of hosting provider we're gonna use hostinger which is also sponsor of this video we're going to talk about hostinger a little bit later i'm going to also show you how you can sign up and how you can go through the whole process setting up your domains and ssls and hostings and how you can connect to your account using ssh and deploy your rest api as well as your front end we're gonna do the whole process but for now let's talk about the things what we are going to learn in this video and the things what are the prerequisites for this video as a prerequisite i only suggest you to have a little bit of knowledge of laravel and a little bit of knowledge of ilpujs if you don't have any prior knowledge of these technologies just don't skip the video try to go with that maybe you understand most of the things if you don't understand you can just start googling and find out on your own just try to follow the video in any case if you are interested of course if you stuck at any point you can check out the video description there is a github link i think there are there are already about 100 comments which i made i plan to continue this process and involve this open source project if you are interested to contribute in this project you're more more than welcome to do so just send a pull request if you if you have anything to modify in the project what are you gonna learn by building this application you're gonna learn how to build laravel rest api with authentication how to work with apa resources how to work with request data how to handle uploaded files and save that on a file system how to generate migrations work with the models how to install composer packages and integrate into your project and there are much more things you're going to learn around laravel in this project as for the front-end side you're going to learn how to set up a project using vite with view 3 and talon 3 which has been released recently you're going to learn how to set up view x and view router with that you're going to learn composition api you'll also learn how to install third-party packages and use like axios for example you're going to learn a lot of vue.js advanced concepts you're going to learn how to create reusable components and there are again much more things you're going to learn but more importantly you will learn how to prepare everything and deploy it on a production i want to ask you one thing i have been working on this project for a very long time and this type of projects requires a lot of energy and time if you really feel that this video is a little bit of helpful just give it a like share and provide a comment even if you don't like something just provide a comment so that that type of activity like writing a comment like or share helps the youtube algorithm to promote my video and show it to others and if you feel that my content is useful i will really appreciate if you subscribe and enable notifications in the video description there are time codes so if at some point you feel that you don't want to watch that section and skip that just check out the time codes and feel free to skip yeah i almost forget one important information i'm going to continue this tutorial series so there will be more videos coming on this full stack application so for example i plan to add authentication using social health and there are a couple of other things i plan to do so definitely subscribe if you are not yet to see more videos like this now let me truly talk a little bit about our sponsor hostinger i am generally skeptical with the shared hosting platforms i have used one of the shared hosting platforms many years ago and it was very uncomfortable for me to work it has it had a very limited access on my php configuration i i could not change my php version i couldn't enable some php functions and i had only ftp and filezilla which i by the way i hate to upload my files on the server so it was very bad experience and since that i always prefer to choose virtual private servers vps it costs a little bit more but i have more control on whatever i do i can set up my server whichever server i want i can set up my languages my databases it's a little bit for advanced people but because i have all kind of configurations i really like vps's but i am using hostinger shared services uh for a couple of months already i am really surprised and impressed so they have really user friendly age panel it's not old-fashioned cpanel and there are a lot of configurations and that's why i'm surprised so i have ssh access full ssh access inside which i have git and composer and php and everything i need i have a user interface from which i can set up my chrome jobs if i need i have php version switcher if i want i have possibility to enable any kind of php extension i want or disable i have possibility to even enable the functions which are blocked by security like shell exec for example or exec and there are much more things which made me impressed and um now i start using lecture hosting for all kind of my websites because i think it's pretty cool i don't have to set up everything on my own and i have also a possibility to control whatever exactly i need that's really awesome okay let's check their main website and have a look at the pricing and everything because in my opinion price to value ratio is just amazing and i really recommend honestly recommend that okay on the home page we see right here basically they almost always have some kind of discount and the premium shared hosting uh just costs 2.5 per month and that includes more than hosting so we can have a look let's click on see all features i want to show that to you so that two point uh five dollar gives you a possibility to have uh those are basically everything ticked it gives you possibility to have a free domain and ssl uh like they are constantly improving their services so like last time i checked that they didn't have that many services and i'm looking for where is domain i want free domain where's that here it is uh no that's not free domain right here so free domain free ssl free uh email if you are a wordpress developer i think this is exactly for you i actually feel comfortable in laravel and deploy my application without any problem but they have very optimized for wordpress so that's the their premium shared hosting and i'm going to select that and have a look how we can actually set up our account so right here we have a couple of options for how long i want to take my hosting by default it's selected on 48 month uh okay i can select to 12 month whichever you prefer uh if you take just 48 month you get a insane discount and you only pay this amount for four years but i think most common will be 12 months for everyone because uh i just generally i take for 12 months okay and we take 31 right here you need to sign up if you generally decide to go with that you need to sign up provide your email right here or sign up with social accounts but one important thing right here in the coupon code section just provide the code holic and that's going to give you 10 additional discount um and since you register and provide some credentials then you will be redirected to an age panel and if you do that i'm gonna see you there after you register during the setup process hostinger will give you a free domain you need to claim the domain and search for your desired one you want when you log in in your hosting your age panel you're gonna see the domain right there once you log in you will see your home page with an overview of your existing and used services right here we see our setup section inside which we have two available ssl certificates you probably see a domain right here in the setup section the free domain you got it we see hosting domains vps and email section here is my domain yourservice.xyz which we need to configure and add it to the hosting let's go through the tab right here with the hosting section right here we see emails which we can configure we see domains we see servers which is for virtual private servers ssl section and few others now i'm going to go in the hosting section and click add website i'm going to specify right here my domain that's going to be your surveys.xyz and the password i'm going to choose some random password which i'm going to copy and save okay my domain has been added right here in the list of websites now i want to add the second website which is going to be api.your surveys surveys.xyz generate another password grab and save this one as well and hit on ed website now i added those two websites i want to go in the ssl section and assign ssl to my websites let's click on setup right here i'm going to choose yourservice.xyz and install ssl on that okay the ssl is being installed let's go back again in the ssl section and choose setup on the next one and choose api your service dot xyz and install ssl right here as well generally hostinger's shared hosting comes with free ssl but if you don't have free ssl or if you want more than one free ssl then you probably need to look for install free ssl on hostinger there are a couple of articles which you can follow for example this one which gives you a possibility to install free ssl from let's encrypt on shared hosting this one uses zero uh zero ssl uh from ssl for free and the domain is ssl for free as well you can click on that and follow just type your domain right here and just create free sl certificate follow all the steps it's pretty straightforward you just need to approve uh the ownership of your domain and that's it you're gonna get free ssl just follow that instructions if you want more than one free ssl okay let's go on the ssl section and we see all three ssls are active now let's actually type your service.xyz in the browser and see what happens we see your account has been created we see default page with ssl secure okay let's try the subdomain api your service.xyz that's gonna work as well alright we have our domains actually ready we have ssl certificates ready we have hosting ready the domains are active now we need to work on the project develop it and finally we're gonna deploy it first of all i'm going to open cmd navigate in the folder i want to create my project then i'm going to run composer create project specify the package name as well as the local folder name or i'm going to install laravel installer globally and then run laravel new and the local folder name in which i want to create my project it's going to grab laravel based project and then install all its dependencies this will basically take several seconds or several minutes we have to wait this and get back when this is done now we need to open xampp control panel start apache in mysql open localhost phpmyadmin in browser from which we need to create our database now i'm going to click new button specify the database name as laravel underscore survey i'm going to choose the encoding to be utf-8 and before unicode ci and then click create button okay i already have my project installed and the database is created now i'm going to open my project using php store it's going to take several seconds until the project is fully opened in phpstorm now we need to start the project for this we need to navigate into projects folder through terminal and run php artisan serve you can do this from cmd or you can do this from phpstorm's integrated terminal i'm going to actually do this from here so i'm going to write php artisan serve which will start the laravels built-in server we can click on the link and the application is open on localhost port 8000. alright we have our application started and now we need to apply migrations if we just run php artisan migrate we're going to see an error this is because laravel is not configured to connect database properly i'm going to use mysql for this project but first i'm going to show you how you can do this on sqlite database we need to open en and in the db connection we need to write a sqlite we can comment the rest of the parameters right here but we need to also create database sqlite file inside the database folder now we can bring up the terminal and run php artisan migrate once again and now migrations are applied successfully which is inside the database sqlite file okay now i'm gonna change the connection i'm gonna delete this file actually and change the connection back to mysql everything basically is the same i'm gonna connect to localhost port 3306 however the database will be laravel survey the username is root and the password is empty i'm going to run php artisan migrate once again and migrations are now successfully applied inside the mysql database we reload in the phpmyadmin and if we open laravel survey database we see all the migrations have been applied successfully okay now i'm going to configure editor config file which comes with the laravel's default installation i'm going to open it and down below right here i'm going to write for any file which ends js or css or less or scss or even view i'm going to set the indent size to b2 and that's basically it now let's generate a viewjs application for this we can bring up cmd once again navigate to the project folder and run npm init vite and the local folder name or i'm going to actually close the cmd and do this from phpstorms terminal npm init white and the view right here it will ask me which boilerplate i want to use i'm going to use view right here it will ask me if i want to use view or view with typescript i'm going to choose view and hit enter the project was successfully generated we can see under view folder and now we're going to run npm install and npm run dev from the view folder as soon as this is done view js server is up and running we can open localhost 8 port 3000 and we can see view is running now we need to install ux for this i'm going to stop the server and run npm install dash s view exact next to install the latest version hit the enter as soon as this is installed i'm going to start the view js server back and now we need to create our viewix store for this i'm going to go inside the source folder and i'm going to create store folder right there and inside the store folder i'm going to create index.js okay right here i'm going to create a store variable using create store function my php storm automatically detects that there exists create store function from multiple packages and i'm going to hit the enter right here and it automatically exports the create store function from vx4me and the create store accepts configuration object inside which we need to specify state getters actions mutations modules and finally we're going to export our store next we need to open main.js and right here we need to import the store from the store folder and after our create up function i'm going to call use on the store that's basically it the store is used now in my store state i'm going to add user and data i'm doing this in order to check if my store state works without any issues after this i'm going to open up view and i'm going to use my state right here for this for now i'm going to use view to syntax i'm going to export default object inside the computed i'm going to write map state and import map state from view x as well and in the map state i'm going to specify an array where we have user okay now this user can be used in the template and i'm going to print this right here let's have a look in the browser and we see an error that's because i forgot to remove setup attribute from the scriptdeck which is composition api now everything works fine okay i'm gonna basically use the hello world component right here under components object okay looks good i'm gonna actually revert everything back i don't need any changes made right here i did this for just testing on the following link from talon css official documentation you can see how you can install tile on css with your vue.js project we need to install several packages i'm going to open terminal and run npm install hd tile and css post css and auto prefixer that's going to install those dependencies after this we're going to install npx town css init p which will install tile and css and post css config files here we can see both of them next we're going to copy and paste the following content array open thailand config.js and replace empty content array with copied one next we're going to create index css and copy the following tile and base components and utilities i'm going to go in the source and create indexes right here and paste my copied styles and finally i'm going to import my index.css in the main.js okay now we need to install a few more packages like headless ui view hero icons slash view and talon css forms plugin okay now i can start my server next i'm going to open hello world component open thetalwindui.com and find sign in and registration pages right here this is a nice example of login form i'm going to go in the code and as we can see this one requires tile and css forms plugin i'm going to copy this code go back in my hello world component and replace everything what i have right there and in the title and config in the plugins i'm going to write require talon css slash forms okay now let's have a look in the browser this is nice form on our localhost 3000. now we need to run npm install dash as view router at next to install the actual view router then i'm going to go in the source folder and under rotor folder i'm going to create index.js right here i'm going to create a constant variable rotor which is going to be a result of create router the create router accepts a configuration object right here i'm going to write history corresponds to create web history which is a function as well and it's going to be imported from the view router then the second i'm going to pass in the configuration object is the roads now we need to create that roads and finally we're going to export the router from this file then we need to go in the main js and just like we imported store we need to import rotor and down below just like we are using store we need to use rotor that's basically all now rotor is used by our view application now let's start our development server once again and we need to configure roads i'm going to go in the index.js from the router folder and create a login road right here path login name is login and the component is login as well however the component doesn't exist yet i'm going to copy and paste this route a few times and i'm going to define dashboard path right here with the dashboard component and register path with the register component as i mentioned the components doesn't exist yet so i'm going to go in the source and create views folder and inside the folder i'm going to create dashboard.viewcomponent i'm going to create h1 with just dashboard text next i'm going to copy and paste this dashboard computer in two times create login and registration and in the login i'm going to just write login in the register i'm going to write register right there now let's go in the index.js to use our created components so we have those right here i'm going to import those components i can write import manually like import dashboard from views dashboard dot view the extension is important or i can let my php storm import for me alt and enter hit enter right here and the import was automatically written now we need to go in the up view and remove everything and create right here router view tag okay now we need to see a result in the browser so right here we see an error i think because the automatically importing doesn't add the extension right there dot view okay here is dashboard slash login slash register everything works fine now i'm going to grab everything from hello world that view copy that and paste in the login.view and paste in the register.view as well however i'm going to change the title for register for free now let's have a look this is how login looks like this is how register looks like however when we access the dashboard page it just shows a dashboard text we need to define dashboard component as well i'm going to go in the tile tylerwindui.com search for the dashboard component in this tech layouts right here we have it nice dashboard i'm going to copy and paste that in the dashboard component and this is how our dashboard looks like however now i'm going to copy and paste dashboard component and call this surveys now i need that header in both pages surveys and dashboard so we need to define layouts okay this nice header i'm going to go in the components and just create default layout.view i'm going to copy and paste everything from the dashboard component into the default layout and i need to from here i need to identify basically where is the content the content is the dashed box and the dashboard header okay so i'm going to grab that header tag as well as the main tag cut that from here and right here in the default layout i'm going to create router view this is where the content will be rendered in the dashboard instead of that h1 i'm going to paste this header and this main tag okay now i'm going to open router file and right here i'm going to define a couple of things first of all i need to redirect slash into slash dashboard then down below i'm going to define the children so first of all i'm going to change also the component to be default layout and it's going to be automatically imported by phpstorm and i'm going to define children roots the path needs to be slash dashboard the name needs to be dashboard and the component will be dashboard okay let's save this i'm going to remove the name of the default layout and this is how our dashboard looks like pretty good we have the same result this is login and we have dashboard as well so if i copy and paste login register and put them as children of the default layout login and registration will also have this nice header this is not what we want at the moment so i'm going to basically undo this change so login and registering is to have a clear layout now i'm going to delete this hello world i don't need that anymore in the surveys.view i need to modify this one as well okay so right here i'm going to just write all surveys so i'm going to display all surveys right here and i'm going to clean up a couple of things so i'm going to remove this data i'm going to remove the components and i'm going to remove this setup as well so basically an empty component now i'm going to go in the rotor and define service wrote right here the name and the component will be service and i'm going to import the surveys component as well so right here i'm going to just duplicate the dashboard and just call it service perfect now if i access dashboard this is how it looks like if i access surveys this is how it looks like so i need to basically have the same type of title as i have in the dashboard so i'm going to grab that header as well as the main however we need to identify where the exact place the exact place where content goes content goes right right here instead of that dashed box i'm going to copy that open this service dot view and paste this right here and i'm going to call this service okay perfect this is our surveys page this is how our dashboard page looks like pretty awesome right now we need to handle the case so that if the user tries to access the dashboard but doesn't have authorization token we need to redirect user to the login page for this i'm going to open the rotor and under default layout road i'm going to add a meter requires auth true i'm basically telling the rotor that this path basically requires authentication okay down below on the rotor before each i'm gonna pass a callback which accepts two from and next so this basically indicates from which road user is trying to redirect on which road and next basically is a callback so right here we need to write an if statement if v2 wrote on which we try to redirect requires authorization and now we need to basically check if the user is not authorized for this i'm going to open the store and right here we have the token and this token basically indicates if the user is authorized or not it's now at the moment okay so we just need to write if store and when i type store it automatically imports that for me if it doesn't import you have to import manually if store state user token does not exist and we try to open the page which requires auth then we redirect user to the login page otherwise we let the user go on the page the user basically was trying to go if we try to access dashboard now we are redirected to the login page if we try to access surveys we are still redirected to the login page however on register we stay there now we need to handle the second case what happens if the token if the user actually is already authorized and we try to access the login page okay we need to prevent this as well and if the user tries to access a login page and it's already authorized we need to redirect it to the dashboard so for this i'm going to write if store state user token exists which means if the user is authorized and the road we're trying to access is either login or a registration we're going to put this in the parenthesis then we need to redirect user to the dashboard page otherwise we let the user go on the page she was trying to access okay now let's have a look if i try to access dashboard i'm still redirected on the login page however if i set some value inside the token now i'm already on a dashboard page i try to log in however it redirects to me to the login page as well as on the registration that's basically the whole setup of redirect flow now let's open our roads and have a look we have two guest roles logging and registration and we are using those roads down below in before each callback so if the user has token and the path name the road name is login or registration and so on what happens if in the future we're going to add other guest roads like request password reset or password reset we have to basically write or statements multiple times so just like we did a default layout i'm going to create right here out layout i'm going to give it a path auth the name will be out as well the component name will be as well auth and we're going to redirect this to the logging path and it's going to have children right here and i'm going to copy and paste these roads inside the children and that's that's i think all i think we're missing component right here so let's put this okay now let's open login and when i remove first of all these comments and let's identify what is content and what is layout so this portion of the code is actually content of the page and everything else inside the template will be a layout basically i'm going to copy everything from here and go in the components and create auth layout i'm going to paste everything right here then i'm going to identify what is content and replace this with rotor view i'm going to go in the login view and remove which is part of layout and that's it and i'm going to do the same thing in registration page basically first of all let's remove all comments and remove part of the layout okay looks good and in the roads we're going to basically import the out layout i'm going to duplicate default layout and change this into of layout and here it is our login works just like it was working before let's actually make some modifications in the login and registration form first of all i'm going to remove this href and change this into a rotor link with the two property goes to the name with a register okay i'm going to change the text as well to register for free i'm going to go in the login and in the login i'm going to change the text to be a login to your account and in the router link i'm going to specify a road with the two property to login page okay let's have a look down below um i'm going to actually remove the password forward password link from both we don't need that i'm not going to implement let's have a look okay this looks good the linking also works fine let's actually create another field in the registration form so i'm going to call this field full name and basically i'm going to replace every mentioning of email to be a name just like this and we have to replace a placeholder as well okay looks good so we have full name email however let's observe this the email address has rounded corners that's because it has a table and css class somewhere okay rounded tmd let's remove this and now it doesn't have rounded top looks good the linking works fine so now let's remove remember me on the registration page we don't need that and the last thing is to change the sign-in into sign up okay we prepared our forms that looks good okay one more addition just like we have mita requires auth i'm going to add mitta is guessed corresponds to true okay using this property i'm going to basically replace right here in this if statement i'm going to replace the basically name comparison to logging and registration with meta is guest so if the road on which we want to navigate is a guest road basically the user is redirected to the dashboard so let's open actually store and i'm going to basically modify the token and write some value right there so the user will be redirected to the dashboard if i try to access login or registration i am redirected to the dashboard page which proves that our is guest property works exactly as we wanted so far i was working in php store and now i open the view as a separate project in vs code okay let's understand the default layout what we have right there so we have bunch of talon css classes right here we have the for loop we navigate we iterate over the navigation array and down below let's actually collapse this and have a look so down below we have the user object with email name and image and that user object is used right here in the navigation we have the navigation array in which we iterate and display those menu items and those menu items are displayed on a mobile as well and we also have the user drop down which is displayed on mobile as well as on the desktop and the notification bell notification icon okay let's have a look in the template as i mentioned we have a bunch of css classes and right here we have the hidden and md block which just displays it on a desktop screens but hides it on a mobile and that's the profile drop down as we see we have these basically menu button which is only visible on a small devices if i just resize this is the button we're looking at right now down below we have this disclosure panel which is has a class amd hidden that one is only visible on small devices and it has its own navigation this one is that navigation down below we have the user profile which is also only visible on mobile and down below we have that user navigation which is this one and that's basically it okay this is how our default layout looks like i'm going to work in the default layout so let me actually first change the token in the viewix so that we have this nice dashboard and i'm going to work on the layout and change the menu items remove the bell icon right here and adjust the user menu as well let's go in the default layout and let's find out first of all what we are using we have the user constant variable right here we have navigation couple of things i'm going to basically cut the user go in the index.js in the store and this data should generally come from the store and now in the default layout i'm going to use these from the store at least i'm going to try to use from the store okay okay let's scroll down below and right here we are using that user variable now i'm going to create a store variable using use store function that user store function needs to be imported let's go up and right here i'm going to write import use store from viewix also i will need computed function to be imported from the view package so i'm going to do that now let's go down again and the user corresponds to computed which accepts a callback function and we're going to return store state user data let's save this and that data basically will be sent to the component and we have an error so that basically i have a typo instead of commuted compute it should be computed so t is missing somewhere so i save that and reload the page and here we have now let's start working on the default navigation so i'm going to remove these links and i'm going to change the hrefs into two i'm going to specify right here name to be dashboard and we don't need the current and i'm going to change the team name into surveys and the href into two which with which will be the name of the road surveys and i'm going to remove current right here as well let's now find out where this navigation is used so this one is one place which uses disclosure button and it has couple of attributes which we don't need i'm going to change this into router link i'm going to remove this as attribute i'm going to change this href into item into 2 and item 2. so first of all we need to add active class right here and i'm going to copy everything right here if the item is current so that's going to be active class and now i'm going to change this item current into something like this if the current road name does not equal to the navigation item name then this means that this is not current and the following classes will be added if it's current empty otherwise the following classes now we need to remove this area current so let's go up and find the second navigation mentioning i'm going to change this into rotor link as well let's change the href into item 2. and do the same thing let's add active class to be the following classes bgray 900 text white and instead of item current we're going to write this road name if that equals to item to name then nothing is added otherwise empty class okay looks good okay let's have a look in the browser we have those two links when we click that works fine if we have a look in the mobile menu those links are working fine there as well now we need to work on the user drop down let's search for the user navigation where it is right here and we're going to remove that user navigation completely and where it is used we need to remove it from all its usages and we need to change so i don't need that v4 basically i'm going to have a single logout button whenever we click on that it's going to call a logout so i'm going to remove those classes okay and this is the item name i'm going to write sign out let's find the second mention of user navigation we're going to remove those things we don't need that instead i'm going to write click logout and let's change this into log out or sign out okay now this is the hour drop down when we click nothing really happens because we don't have the logout function implemented yet okay let's add a cursor pointer to the logout button as well we need to add this in both places okay we have this nice cursor on desktop and on mobile as well now i'm going to remove the bell notifications button we don't need that i'm going to find the second place where this is used and we're going to remove it from there as well now it's time to implement logout right here i'm going to create a router constant variable using use router function and we need to import that use router from the view router package and i'm going to create logout function right here i'm going to call commit onstore logout which will basically commit a mutation and whenever user is logged out we're going to redirect user to the login page and down below we need to return that logout function to be accessible in the component now let's go in the store and i'm going to create a logout function logout mutation which will accept a state and i'm going to basically reset the user data and the user token right here now we save that and when we click logout we are redirected to the login page which proves that this works fine if i go in the store and change the token into null we are basically on a login page by itself if we change this into something we are on dashboard page however if we click logout we are on a login page sorry for disturbing you if you enjoy this video so far just give it a like and subscribe continue please we have two views very similar to each other surveys component and dashboard component if we have a look in the browser we navigate we see they are identical just the text is different also if we observe the html we see that everything is identical only this one is different so it would be nice if we create a reusable component and just pass title right here and we're going to do this right now i'm going to go in the components and create page component dot view first of all i'm going to generate a boilerplate code right here template script tag and style the scriptdeck has set up which indicates that this is a setup method of composition api then i'm going to go in the dashboard and copy header in the main and i'm going to go in the component page component and paste it right here then i'm going to remove this content goes here and dashboard texts okay after this i'm going to define props the define props function is a function which doesn't need import in the composition api and using this approach we define props and right here we accept the object the same object you would give in the options api we define the props we have title which is a string okay after this we can already use the title in the template so i can use the title right here and down below where the content needs to go i'm going to use a default slot okay now on the dashboard component i'm going to first import just created page component then i'm going to add a setup attribute on the script tag then i'm going to replace this header in main with the page component we're going to give it to title and the content goes here it's going to be what will be injected inside the page component slot and finally i'm going to remove its export default i don't need that i'm going to format the code save this and have a look in the browser this is our dashboard look at this how small this is so i'm going to copy this and go in the surveys and replace everything and inside the title i'm going to give it surveys later if we might need we can create another slot which is going to be the name slot to display some html alongside with the title so far this looks good and it works fine now let's generate migrations for this i'm going to bring up terminal and run php artisan make model survey dash m i'm going to hit enter this will generate model as well as the migration and we're going to generate other models and migrations like we're going to generate survey questions or survey question dash m we're going to generate survey answer dash m and we're going to generate survey question answer dash m okay now let's open migrations under database migrations folder and let's actually start with the survey first and define the fields okay first of all i'm going to define a user id for in key which refers to the app model users next i'm going to define title with the length of 1000 i'm going to define also slug with the length of 1000 i'm going to define status which is going to be tiny integer and i'm going to define description which will be nullable and it's going to be text and the timestamps is automatically defined by the laravel migration tool and down below i'm going to define expire date that's all for the surveys table let's now open the second table which is survey questions here i'm going to define a type with the string and the length of 45 i'm going to define a question string with the length of 2000 i'm going to define long text description and long text data and both of them will be nullable and i'm going to define foreign id for the survey class and the column name will be survey id that's all for the survey questions let's now open the third one which will be survey answers table for the survey answers we don't need timestamps so i'm going to remove that instead i'm going to add following id for this array class with the survey id column i'm going to add the timestamp to be just start date and nullable and i'm going to add second timestamp which will be the end date and nullable as well and that's it for the survey answers let's open the last one which is survey question outsource table here i'm going to add foreign id for the survey question with the survey question id i'm going to add a second foreign id for the survey answer with the survey answer id and i'm going to add text which simply will be an answer okay here we have all our immigrations and models generated you can find the models in the up models right here and now we need to apply migrations so i'm gonna run php artisan migrate hit enter on that and immigrations were successfully applied now let's create out controller and implement registration under up http controllers i'm going to create new php class and i'm going to call this auth controller i'm going to extend this from controller up http controller now right here i'm going to create a register method the register method accepts a request argument so we the request instance basically has a methods like validate for example so we're going to call validate on that and pass the validation array inside the array we're going to define couple of validation rules for example name and email in this case we indicate that the name is required in the string email is required it must be valid email address it must be string and it must be unique across the users table inside the email column we're going to define right here password as well to be required and confirmed confirmed rule basically indicates that there must be a second field password confirmation okay and right here we defined that the password should be minimum 8 it should be mixed case uppercase and lowercase it must contain numbers and symbols as well so we define all our validations down below i'm going to already call user create we're going to pass this data and whenever the validate is called inside the data we're going to have already validated data so we take name email and password however we encrypt the password and give it and user is created for like for id purposes sometimes i add this annotation which tells the id that the user is an instance of app models user okay down below i'm going to call create token on the user give it a name main and i'm going to take this plain text token and down below i'm going to return a response as an array with the user and the token so when the user is registered we're going to get user in token on the front-end side okay we have this method ready but don't forget to write use statements right here so we need to use up modules user and illuminate http request for this one and eliminate validation rules password for the following class the last thing we need to do we need to go in the roads api and right here we need to define a route i'm going to define a post road right here because we should only make post requests on the register we should not make get requests the endpoint will be slash register and we're going to pass right here in array out controller class and register just make sure the auth controller is used properly i'm going to hit alt and enter and php store will automatically import that class for me you can write this manually okay now our registration endpoint is ready and can be used now since we have our backend ready we can work on the front-end side so i'm gonna open registered view and i'm gonna add right here a couple of things first of all let me actually open store index.js and i'm gonna set the token to be now and i'm going to make this data as an empty thing by the way this data has image url which we don't need and we need to handle this case as well so i'm going to make this as an empty object save this and in the browser we see a login page because the token is not let's go on a register page and we need to add one additional field which will be password confirmation i'm going to open register.view i'm going to duplicate this password field and i'm going to change a couple of things with just one run a password underscore confirmation okay i'm gonna change i'm gonna put the label con for mason save this and have a look in the browser we see this nice password confirmation look at this the password field has round bottom so we need to find that class in the title on css that's going to be rounded bmd and remove this and now we have these nice inputs and now i'm going to add v-modal to all these fields but with before that let's scroll down and have a look in the script area first of all i'm gonna change this into composition api setup so i just add a setup attribute and i'm gonna remove this export default as well this one is imported and it can be automatically used without anything now i'm going to define a user object right here with name email password and password confirmation then i'm going to define a register function which i'm going to add later on the submit event of the form of the registration okay after this i'm going to import my store because i'm going to use that and on the store i'm going to call dispatch passing the register action name the action doesn't exist inside the store yet but we're going to create that soon in the dispatch i'm going to pass also the current user which i want to register this register action should return a promise and on that promise i'm going to call then and inside then i'm going to do a rotor push so basically after the user has been successfully registered i want to navigate user somewhere so i will need the router so i'm going to use router from the view router and i'm going to create also rotor using a reuse rotor function basically i'm not creating i'm using an existing rotor okay and down below right here i'm gonna provide the name of the road in which i want to redirect user and that's the dashboard right now so let's take this register and find the form and inst instead of the action and the method i'm going to write submit register okay and i'm going to define also v models for every field we have right here v model that's going to be user password confirmation and this one is password confirmation but the other one this one will be just password this one will be email and here we're gonna have name now let's go in the store and implement that action now i'm gonna define right here a register action which accepts an argument right here and i'm gonna destructure that argument and take out a commit using commit i'm gonna basically call them function from the mutations okay we're gonna get a user as an argument as a second argument in the register and then right here i'm gonna make an http request for now i'm gonna use a fetch api for http requests but i'm gonna replace this later with axios and we're going to see advantages of axios compared with fetch api there are some limitations and things that should not work in the way it works in case of fetch api but so far we're going to call a fetch method passing the url and configuration object inside the object i'm going to specify headers with content type and accept both to be application json i'm going to specify method to be paused and body will be the user object but the stringified version this one will return a promise so i'm going to call then on that and i'm going to call on the result json which will finally give me the result i want and right here i get this result and i'm going to call commit so the set user i'm commenting the set user mutation passing the user information the set user mutation doesn't exist yet but we're going to create that and finally i'm going to return the results just in case this is necessary in the places where the register action will be dispatched so in the register view down below right here we can technically get that result if we want okay now let's create that set user mutation okay here i define set user mutation we accept the state as a first argument in mutation you always get the state and the purposes of the mutation is to just change this state but we pass the second argument result from here so we accept that as a user data and now i need to save the received user token in data inside the state so i call state user token equals user data token and this token will be token returned from the php laravel controller next we save the data as well to be user data user and finally we're going to save this token in a session storage as well so if we just reload the page the token needs need still to be available and the user needs to stay on the dashboard so let's scroll up and right here i'm going to write session storage get item and i'm going to pass token right here okay just like this the token will be saved in a session storage and i will not be logged out since i'm registered now it's time to test all this let's open the browser and fill up the user information okay let's open the developer tools let's go in the network and let's hit the sign up button and let's see what happens yeah we have been successfully registered and we are redirected to the dashboard page let's have a look what has been returned okay here's the preview we got the token we got the created at and everything basically about the user so this proves that we have been successfully registered now if i just reload the page i stay there because the token is saved in session storage however if i just click on logout so this does not clear from the session storage so far so if i just reload i'm still logged in now let's create a login endpoint in the auth controller in laravel so first of all let's create an empty function login which accepts a request right here and i'm going to call validate on the request and save the result in the credentials variable in the valid data i'm going to pass email password and remember the email basically is required email string and it must exist in the user's email column that's important thing next i'm going to take out the remember in a separate variable and unset it from the credentials and right here i'm going to call auth attempt which accepts credentials and remember so this will basically take the credentials and attempt to log in the user if the credentials is incorrect it's gonna return false if it's okay then the user will be authorized in the system with the corresponding remember me value true or false if the attempt returns a false we're gonna return a response immediate response with a json error the provided credentials are not correct with the status code 422 which means that the validation was not successfully passed down below i'm going to get the authorized user which means that the user has been successfully attempted and authorized and i'm going to generate a token on that user and i'm going to get the token and finally i'm going to return response with the user and the token the same response we are basically returning let's scroll at the top and we need to uh import one class which will be illuminate support facades out which is for just calling the attempt method now let's open the api php and right here we need to register login in the same way we are calling uh registering a register action so just like this we have the login save it and now we can test this on the front-end side now on the front-end let's open login.view and we're going to implement the authorization let's have a look on the front-end side so we are authorized i'm going to actually clear the session storage so that i am not authorized anymore i reload and i'm on a login page and now let's work on this so here's our html and let's scroll down below and i'm going to define a user constant variable right here it will be pretty much similar to the registration first of all i'm going to add setup right here and remove this export default let's define a user variable right here with email and password then i'm going to define a function login which i'm going to use later in the template i'm going to import now store from the store file and i'm going to call dispatch on the store with the login action i'm passing the user it's pretty much the same we did for the registration we don't have that login action at the moment but we're going to create this right now so then this dispatch will return a promise and on that promise i'm going to call then inside this thing callback i'm going to basically uh do a redirect so i will need to use the rotor so i'm going to use rotor import use rotor function from the view router and i'm going to use the rotor actually create a variable rotor and down below i'm going to call rotor push with the name dashboard so whenever user successfully author authorizes it basically goes to the dashboard page on the user field we also need remember property so we're going to add this one as well now let's scroll up and adv model on email password and checkbox as well so v model equals user dot email and let's change this into password and this will be remember now let's open store and we need to implement login action right here so i'm gonna duplicate this but let's have a look now we're using fetch and if we just duplicate this we have couple of repetitions like we are passing headers two times we are passing method paused two times and we have a lot of repetition like for example getting getting the actual response json is also something uh which is repeated and we don't want that also in the future we will need interceptors interceptors are special functions that will be used by the package itself before we make a request or after the response or before the response is actually taken out from us after it actually returns so we need to do a couple of interceptors so i'm going to install axios right now i'm going to bring up terminal and actually kill these developer tools and i'm going to run npm install s axios okay let's start this server now i'm going to create a axios http client let's do this inside the source oops it's open and inside the source i'm going to create axios.js okay first of all i'm going to import axios from the axios package next i'm going to create axios client and i'm going to pass base url right here which will be the laravels api okay next i'm going to export that axios client which i can already use in any place in my project but i'm going to show you an example of interceptor as well because we're going to need that so for this i'm going to import the store the store basically contains a token authorization token so we will need that right here i'm going to call axios client interceptors request use and we're going to pass right here a callback which accepts a configuration object and first of all we're going to return that configuration object but we're going to inject the authorization header right there so config headers authorization equals bearer and right here we need to specify the store state user token so that's the authorized user's token so on every request axios will make it's going to pass that authorization token so we need to save this information go in the index.js and instead of fetch i'm going to change this now into axios so first of all i'm going to write import axios client room let's go one directory back axios and right here let's change this so i can actually change almost everything let me actually clean up everything first of all for registration and we need to call this login and i'm going to clean up everything right here as well okay let's do login first so i'm going to call axios client post pass the path of the url slash login and pass the user we want to pass to the endpoint and we're going to return everything from here by the way because finally we're going to return promise from this actions viewing section okay then right here inside then we accept a response so i'm going to basically destructure the response and take out the data axios response contains data inside which is the actual data actual response body we are interested in so i'm going to return that data because just in case someone else who is using this login is necessary and also i'm going to call this set user and passing the data set user already exists which accepts that data and takes out the token in user and assigns it in the viewix basically that's all for the login and i'm going to copy this and paste this right here and just change this into register okay now let's open the browser and try to log in with the previously created user i'm going to open the network as well and i'm going to specify my user and my password hit enter on that and something happened i think i know what happened because on the form we don't have proper submit event we're going to call login right here let's remove the hashtag hit enter let's provide username hit enter and we are redirected to the dashboard which proves that the our access client not only our access client works fine but our application authorization works fine as well right here we click we see that we go we got token we got the user information as well now i want to test registration as well so let's actually clear up our session storage reload the page let's go on the registration because we change that using axios and i'm going to create uh with one of my emails hit enter on that and i'm registered and i'm redirected to the dashboard looks awesome now we need to test one more thing or not test but implement one more thing so if we go on the login page and try to now log in with invalid credentials we get some information from the backend let's have a look what we do yet so we get the following information error the provided credentials are not correct this is the error we wrote we wrote in the out controller but we don't handle this properly how we're going to do this if we go in the login component right here and down below on this we basically need to catch an error so right here i'm going to define a variable error message variable and i'm going to display that error basically to the user that the user needs to know if the username or email or password is incorrect so i'm going to use a ref i'm going to import rev function from the view and i'm going to create a variable error message using this ref down below whenever we call the dispatch login inside right here so in the then we redirect user to the dashboard but we need to catch this properly so i'm going to write cache and we accept error right here so now i need to assign this error to the error message because we are using refrain here you cannot assign it to the error message directly that's the nature of the composition api that's how it is implemented and instead we're going to need to do error message.value equal equals to error but this error is a javascript error class instance so we cannot just assign it it doesn't give us the valid information we need to take out the actual error information which is returned from the following request so this error basically has a response so we need to access response the response has a data the same data like we accessed right here using the structuring okay so we access that data and this data is an actual response the the following response okay and now we can access an actual error message from this data so we save this and we can now display this error message somewhere let's just directly write error message pay attention that when you're writing a variable created using ref you don't need to do a dot value right here in the template you need to do this in the javascript but not in the template so i save this i go in the browser and let's fill up some information with invalid password hit sign in and we see right here the provided credentials are not correct now i'm going to add a little bit of styling to the following html so first of all i'm gonna wrap it inside the div and if the error message exists only in this case we need to display it okay and let's add a little bit of styling to this tip so i'm going to give it a padding uh horizontal and vertical as well i'm going to give it a background red text white and rounded let's have a look in the browser how this looks like this looks already pretty cool so that's exactly how i want it but i want to add a close icon right here so whether whenever i click on this icon this um alert or this error message simply disappears so for this i'm going to create a span right here and whenever i click on that spawn i'm going to reset the error message so our message equals to an empty string this looks good next i'm going to add display flex item center and justify content on the error message elements just to show this close icon and error message next to each other then right here inside this pan i want to put a close icon so i'm gonna go inside hero icons click on that and search for close and let's copy this one and this is our close icon and i'm going to add a couple of classes in this pan as well so like i'm going to give it a width and height to be h so i'm going to save this and have a look in the browser this is our x i want it to have a circle around it when i mouse over on this and i'm going to add a transition and make it like wind it properly in the center so i'm going to add flex item center and justify center and this is how it looks like and i'm going to give it a rounded full and i'm going to give it transition colors cursor pointer and on mouse over i'm going to give it background to be transparent dark okay i save this and when i mouse over this is how this looks like pretty awesome when i click on this error message disappears click on this it appears okay this is pretty cool so we have implemented login and displaying error message as well so if i just provide correct password right here hit enter on that so we are redirected let's actually test how remember me works if that actually causes maybe maybe an error so let's have a look remember me hit ok oops i incorrectly typed my password hit enter and i'm redirected to the dashboard this looks good now let's open out controller and implement logout on the backend side i'm going to create an empty function log out then i'm going to get the current user using auth user and i'm going to add right here a comment for the ide that this is an instance of the app models user and then on that user i'm going to call current access token delete it is as simple as this which basically will re revoke the token that was used to authenticate the current request okay and down below i'm going to return a response with success true we have already imported that out in the in the controller which is a facade's auth illuminate support facades off and that's it our logo works now we need to go in the api and right here add a wrote for logout here we already have protected road on get users basically because this is written after the middleware out sanctum we need now a second protected road for logout the logo should only be made with the authorized users like we can duplicate these uh but i'm gonna show you a better way so basically i'm going to create a group right here the group accepts a function closure i'm going to pass the closure and i'm going to define road get and basically the following the following gets so this will be moved right here and deleted from below and after this this works in the same way as it was working before but we have these roads inside the group now i'm going to add logo right here which will be out controller logout so i save this and now we can use this on the front-end side now let's have a look at the logout function in the default layout which commits a mutation logout mutation and redirects user to the login page if we have a look in the store index.js scroll down below we see this logout mutation so i'm going to add a logout action right here but first let's have a look in the logo the function in the default layout i'm going to change this into dispatch which obviously will have a then right here because we're going to return promise from there we accept the callback and i'm going to do the rotor push inside the callback whenever backend returns that the token was successfully deleted whenever the token is also deleted from the session storage which we're going to do in the action of the store then only after this we need to do logout or redirect okay let's go in the store and right here i'm going to create a logout action and i'm going to accept comment then i'm going to call axios client post on the logout action and return whatever is returned i'm going to add a then callback right here passing the accepting the response and i'm going to return that response and i'm going to also call comment on logout now let's have a look in the browser and i'm going gonna open the tools and i'm gonna click on sign out right here and i was redirected to the login page which proves that our logo works fine now let's start working on the surveys page now let's start working on the surveys page first of all i'm going to define a json template how the back end should return response to the front end and first of all i'm going to render the data based on this json on the front-end side and then we're going to jump on the back end and implement so that the back end returns the data in the same format we define okay now right here above the store i'm going to define a constant variable tnp service that's going to be an array of surveys and now let's define each individual survey so we're going to have id for each one in title and slide as well status will be either active or draft image url so we have not implemented we haven't added image column in the database table but we're going to add this later we're going to have description we're going to have created it updated it an expired date until which time the survey is actually valid and each survey will have a questions array and inside that questions array we're going to have an object of questions for example first one is a select type of question and the question is from which country are you the description in this case is now and each question might have optional data the data will be either empty object or containing some additional information about the question in this case because this is a select we're gonna have options inside the data so options will be an array inside the data and inside the options we're gonna have objects with uuid and text why did i choose uid because it's much simpler to generate random uuids than random ids okay we might have collision when we generate ids on the front-end side so uids is easier and safer okay each option will have uid and text usa georgia germany india or united kingdom okay i'm going to define a few more questions inside the survey and then see how we can just get the data in the surveys component or just iterate over those okay we're going to have checkbox which have a question and description and data checkbox select and radio questions are pretty much identical all of those questions need options array so we have options right here let's scroll down we have another checkbox which has also options you can pause and read those are actual questions and scroll down and right here we have radio with additional um like its own options and down below we have another checkbox and down below we have one text field which is a standard single line text field with description null and empty data and down below we have another field which is text area okay so those are all the questions for the first survey and i'm going to define other few other surveys and see how those will be rendered in the list like this one is the level eight survey view three and taiwan three so those are all the surveys i define and then now i'm gonna take this that tmp this variable tnp surveys and i'm going to use it right here inside the state okay i'm going to define surveys array right here inside the state and i'm going to take the tmp survey and just structure it and design into surveys okay using this approach i have basically guarantee that surveys will have some data right there and i'm going to take this data in the component and just use it okay this is the place we're gonna render our surveys i'm going to also add a add new survey button right here in this header on the right side so i need to update my page component because because the page component takes title prop at the moment and if we just open this we have only title right there and just display the title we have no possibility to add a button inside that header area which is right here so basically i'm going to modify this and add right here slot property slot tag basically with the name header right here i'm going to remove the title attribute i don't need that anymore i'm going to replace the content goes here with a template with this load header and whatever i put inside this vsload header that's going to be outputted right here in this slot okay i'm going to put h1 right there and let's actually save this and have a look in the browser so this is how our page looks like so the title is already taken and works fine next i'm going to wrap this h1 in a div with flex and justify between and item center because i'm going to put button right here okay i'm going to put a rotor link with the two with the name survey create we don't have survey create road yet but we're going to create this soon now i'm going to go in the hero icons and select a plus icon and paste it right here and we it will have a height of four with a four margin of minus one in inline block to align it properly and our header is fully ready now i'm gonna open a rotor and i'm gonna create define that survey creation wrote so basically i'm going to create right here path surveys slash create with the name survey create and with the component survey view the component doesn't exist yet but we're going to create it after we create roads i'm going to also define second road which will be for survey update it's going to have id in the url so the survey id the name will be survey view however i'm going to use the same component survey view component so even though we don't have that survey view component created i'm going to write an import right here from the views i'm going to import survey view dot view file now let's create this component let's go in the views click plus right here and create survey view dot view file here first i'm going to define a template and i'm going to use page component i'm going to give it a title as well as the content inside the page component and i'm going to import the page component from components page component we save that and let's have a look in the browser so we see surveys page right here with add new survey button which looks awesome now we can go on surveys page iterate and just render surveys now let's get surveys from the viewics i'm going to import store first of all then i'm going to import computed from the view and i'm going to create a surveys constant variable which is going to be computed store state surveys now let's go in the template and simply print surveys right here let's have a look in the browser here are our surveys so we got all of them now i'm going to create a d right here which is going to be a wrapper for every survey on that div i'm going to add several talon css classes like i'm going to give it a grid grid calls one gap three on small scripts on small uh about abouts [Laughter] [Music] above small screens i'm going to give it call grid calls 2 and above medium screens i'm going to give it columns of 3 so that's going to give us a responsive nice layout down below i'm going to start iterating over surveys i'm going to add key to each div and classes as well give it a flex flex column padding some shadows background and i'm going to give it a fixed height of 470 pixel down below i can display already an image of this uh survey i can display title of the survey and description all right let's save and have a look in the browser this is how it looks i think that's pretty cool also this is responsive so if we just resize it on different screen sizes we see that nicely down below the description i'm going to create a 1d which is going to be wrapper for the buttons and i'm going to have two buttons edit button and delete button right here so i'm going to give it a flex justified between item center as well and a little bit of margin top inside there i'm going to create a rotor link which should have a 2 on a survey view but we're with param survey id that's going to redirect give us the survey information survey id and we're going to fetch the current survey from the backend so i'm going to add a couple of classes taiwan css classes for nice styling and i'm going to also add right here an icon svg icon that's going to be pencil icon you can grab this from hero icons down below i'm going to add another button with the click event handler on that survey delete survey this function doesn't exist but we're going to create it very soon let's give this one classes as well and down below i'm going to put right here a trash icon okay let's save this and have a look in the browser okay this is how our edit and the delete button looks like so if i click edit i'm redirected to survey view or create page which looks good and whenever we click on this nothing nothing really happens at the moment because we have not implemented this so let's scroll down below okay down below i'm going to create a function delete survey i'm going to accept survey right here and i'm going to show a default browser's default confirmation if user really wants to delete that survey because this cannot be undone and at the moment i'm going to write a comment right here but basically we're going to implement actual survey deletion so whenever i click on this button i get this nice notification when i click this survey should disappear so we're going to implement this a little bit later now let's work on the create or update survey page first of all i'm going to define a model variable right here and i'm going to bind this into the form later the model equals to ref and the empty object ref i'm going to import ref right now so inside the ref and object i'm going to pass title status description image expire date and questions those are the fields each survey needs to have okay and now i'm going to import ref from the view i'm going to also import store from the store because i'm going to need that and i'm going to import use road from the view router and create a road use the current road so this one is a model for a new survey form but we need to handle the case when we open edit survey page in this case we're going to have road harms id if the road perms id is presented then the model's value i'm going to update the model's value to be from the store state surveys to find a survey which has the same id as the road params id so i find that survey and assign it into model's value all right so far so good we have the model in all cases and now let's scroll up and work on the template so let me actually remove this title and this content i'm going to create a header b slot template inside there i'm going to create a wrapper div in h1 inside i'm going to check first of all if model has title then we're going to write modal title but if the model doesn't have id then we're going to write create a survey so if we're updating the survey we're going to display the models title otherwise we're going to write create survey let's move down below and we're going to create form on the form i'm going to add a save survey i'm going to call save survey on forms submission i'm going to prevent right here as well i'm going to create one wrapper element i'm not going to actually explain every taiwan css class you can of course find out in documentation don't try to learn them by heart but yeah as you can see guess like this one is a little bit of shadow this one will add border radius and overflow hidden on above the small device so most of the classes are basically self self descriptive okay now i want to right here define another div for the survey fields like we're going to have image title description expire date and status okay and down below we're going to have area for the questions i'm going to add a couple of classes right here on the steve as well and let's start defining image field first of all i'm going to create a wrapper d for every element inside there i'm going to have a label with a couple of classes like font medium text gray and so on and i'm going to call this image so down below i'm going to have another d wrapper div and inside there i'm going to render an image tag if the model has image in most cases it's going to be the update survey case so if there is already image presented we just display that otherwise we're going to display a span tag with bunch of classes so i'm going to you can grab that template from the talon components library so if you go on the taiwan ui.com and forum section click on this so you will you'll find a lot of examples right here and this is this is one what we are using at the moment so if you go in the source code you can observe this and find out that image area okay photo area okay that's we're creating basically something uh similar to this one if we are just uploading a new image okay let's go back into vs code we added a couple of classes right here uh and down below i'm gonna uh put an image uh and i'm gonna get you can get this image from the halloween ui thailand uh ui sorry from hero icons so if we just go in the hero icons and type here image that's going to be the image i'm using right here i'm going to add a couple of classes to this svg i'm going to give it a hate and with 80 text grade 300 and down below i'm going to create a button as well that's going to be the change button give it a bunch of css classes and inside that let's have a look so far how this looks in the browser so this is how it looks it's pretty identical with what we have right here but whenever i click on this button nothing really happens so we want the file um oh pickard to be displayed basically so i'm going to display i'm going to add right here input type file and if i just save this look at this how ugly this is so i'm going to add a bunch of css classes absolute and anything basically and now if we have a look and i click on this change it triggers that file picker okay looks good now let's move on on the second field which is title so i'm going to create a wrapper do for that i'm going to create a label with css classes i'm going to create input with type text and look at this tv model basically goes to the modal title and inside css classes i'm going to add nice css classes as well so if i save this and have a look this is how our title looks like in the same way we're going to define now description with label classes wrapper for the text area in the actual text area save that and have a look we need to add css classes to those exterior so save this and have a look this is how it looks like so i'm going to continue and create expired date with label input and input classes status status is basically a checkbox so i'm going to create 2d wrapper elements right here the first one we're going to have input type checkbox with classes in the second one we're going to have label and that's it okay if we have a look this is our checkbox and down below we're going to create one div element which is going to be the footer of the form with a bunch of talon css classes again and basically every element will have several at least like two or talon css classes okay and we're gonna have bunch of classes on that button and that's it so let's have a look this is our save button we can actually print the model whenever we change something and have a look i'm to go up at the at the top and right here above the form maybe in the pre tag inside the pre-tag i'm going to write model so let's save this and have a look this is how our model looks like when i start changing something look at this the model updates inside the description if i change status it's going to change the status into true and everything basically works so far now let's have a look how this works on when we try to edit existing survey if i go in the surveys and click edit right here look at this so it displays an existing image populates the title description the date is probably not correctly set that's why it's not actually set now down below the survey fields i'm going to start iterating over the questions and render the questions editor inputs okay so first of all i'm going to create one wrapper div inside there i'm going to create h3 with the text questions i'm going to add this a button as well next to it it's going to be add new question button let's add a bunch of talon css classes and i'm going to add right here in svg icon for the plus so if i save this and have a look this is our question section with this nice button okay down below i'm going to first check if module questions length does not exist then we're going to display you don't have any questions created so we are not going to see this because this survey has actually questions but if we go in other surveys and click any any basically without except the first one we see that you don't have any questions created or if we just create a new survey we're gonna see this one right here okay now let's continue and i'm gonna i'm gonna start iterating over modal questions get the question in the index and i'm gonna create separate component for each question editor and i'm gonna call this exactly the same thing question editor and i'm gonna pass this question editor the current question as well as the index and the question editor should trigger a couple of events when the question was changed or deleted okay so we're going to listen to those events right here in the survey view component on question change on add question i'm going to add each question editor button to add another question so we're going to listen to the add question as well and we're going to of course have delete question so just like this we prepared most of the things in the survey view now let's create this question editor component let's go in the components and i'm going to create basically a subfolder editor in inside i'm going to create question editor.view and let's work on this right now let me first generate boilerplate code and now first let's start working on the script side i'm going to remove this i'm going to give it a setup to use composition api in the setup i'm going to define a couple of props define props can be used without import that's not necessary i'm going to pass object right there and define question needs to be an object and index needs to be in number i'm going to also use a built-in function define emits and i'm going to pass right here change at question and delete question which tells basically the parent component that this component emits might emit the following events okay we're going to save this in an emit variable and we're gonna we're gonna need that later okay down below i'm gonna recreate the whole model using json stringify and json parse so this one uh this uh jsonparse and json stringify is necessary to lose the reference to the actual question object okay because we're gonna update that model and we should we don't need to have an actual reference because that might give us some unintentional changes by reference and because we are using ref right here we need to import that ref from view let's actually import just created question editor in the survey view so down below the page component i'm going to import that question edit now let's work on the template side so i'm going to define a wrapper element and right here we need to display inside h3 the question text and i'm going to also display the question index plus one because the first index will have the first question we'll have index zero and i'm going to display the one right here so we display a module question as well down below i'm going to define a section for two buttons add new question and delete question each question will have basically a button to add a new question which will add a question after that question okay then down below also i'm going to define another section for the questions and for the question text and the question type and at the very bottom we're gonna have question description and down below we're gonna have also data for the questions but let's start with the button first i'm gonna add a new question button right here with the click event handler and this add question function is not defined yet but we're going to define those functions later and i'm going to add right here an svg icon plus icon and i'm going to give it uh taiwan css classes okay down below let's define delete question we're going to give it a classes and put there a delete trash icon as well and down below we're going to define now question d element inside there we're going to have label with a question text and down below we're going to have input with title and css classes and down below we're going to define question type and the question basically question text and question type will be next to each other we can have a look how this looks so far so we see this is a question text with the add and delete buttons this is uh the the same question text basically and right here we need to define question type okay so here we have that label select which should have an options okay let's first give it uh let's start iterating our options question types the question types is not defined yet but we're going to define this soon first of all we're going to define in the view weeks and then we're going to use that later in the view weeks we're going to define question types in the viewix and i'm going to use it right here in this component okay i'm going to start iterating the question types and i'm going to convert each question type into its upper case first case uppercase version first letter uppercase version okay i'm going to add css classes to this select as well and let's move on the description create a wrapper element right here and give it a label and text area with a bunch of talon css classes let's save this and have a look how this works in the browser here we have that this is a question type we don't have any options text description to separate one question from another i'm going to hit right here hr tag as well so that we have this nice horizontal line let's start working on the question data first of all i'm going to create an empty d which is going to be the container for all kind of question data at the moment we only have options inside the data but we might have additional options later additional data attributes okay inside the data i'm going to create additional d which is going to be the wrapper for the options i'm going to check if the question should have options this function doesn't exist yet but i'm going to create it right now and this will check if the question type is select or radio or checkbox and basically this means that the question should have options inside there i'm going to create h4 tag with tile on css classes instead of that h4 i'm going to add new option button as well which will have a click handler to add option function which doesn't exist yet that we're going to create and i'm going to tile on css classes right here as well and i'm going to add a svg icon for plus okay let's continue and down below i'm going to check if the modal data options length does not exist which means that the if the current question doesn't have any kind of options then we're gonna display text right here you don't have any options defined okay otherwise we're gonna start iterating over our options list inside the v4 we're going to write to take out the option in the index and start iterating i'm going to use the option uid as a key i'm going to add a couple of talented classes and down below i'm going to display first of all the index of the question and then i'm going to display the input with the data change event handler and down below i'm going to display also a delete button for each option okay it's going to be normal button with challenges classes and svg icon inside let's have a look how this looks so far in the browser okay we don't have any options let's reload the page we actually have an error because should have options is not a function so we need to define couple of functions now let's scroll down below and create those functions like add option remove option data change as well as should have options first let's open store and inside this state we're going to add question types now let's use those question types in question editor now inside the script tag first of all i'm going to import computed property and i'm going to import store as well and down below i'm going to get question types from viewix i'm going to call computed and pass the callback return store state question types which we just created right here then let's define functions so i'm going to define uppercase first let me actually show split this and show on the right side as well so if we just scroll up we're going to see uppercase somewhere here it is so here how we display the type so i'm going to define that uppercasefirst function i'm going to return the first symbol take the first symbol charge 0 convert into an upper case then i'm going to take the rest of the things and concatenate it with it okay it's down below i'm going to define a function if the question should have options and i'm going to check if the question type is one of those select radio or checkbox okay and this will return either true or false let's continue and i'm going to define git options and set options every time i need to get or set options i have to write modal value data options so i create those two handy functions getters and setters down below i'm going to add add option function which will take an empty option and edit so i'm going to call set options but first of all i'm going to call get options i'm going to destructure that and then add one additional one additional uh option right here and we need to uh give it a uuid so this function doesn't exist but we need to import that i'm gonna do this right now so let's let's continue and i'm gonna trigger data change after all these the data change function will be created soon now let's define remove option i'm going to get a call get options filter those and take out which is not the current option and just assign it into the set options okay i'm filtering every option which is not this one what i want to delete right now so finally we're going to have a new options list which doesn't which doesn't include this one okay and then finally i'm going to trigger data change let's continue and i'm going to also listen to the type change when the question type is changed and i'm going to check if the question should have options in this case i'm going to call set options and i'm going to read basically if there exists any existing options or assign it an empty array why do i do this because whenever the question type is select or radio it has couple of options if i switch back to switch to text the text doesn't have options but i don't want the options to be lost if i switch back to the select or radio i want those options to be still presented so this is how we do that i'm going to show this in action let's scroll down and i'm going to trigger data change and i'm going to define right here data change function which emits the data change and i'm going to take the modal value and i'm going to also check right here if the current question should have options if it should not have options basically i'm going to delete data data options here's one important things so far let's have a look in the browser so this is uh we haven't er i think let's let's reload the page we don't have any errors okay here are our options rendered nicely we have this delete options button which i guess works fine so if i just change the type into text the options of course disappear if i change that back now we lost our options why does this happen because right here we get the data by reference the model value and we actually delete the data data options which basically lost lost the data okay we don't have that we can't recover this so right here i'm going to wrap this model value into json stringify and then json parse which creates a clone of this modal value okay and now if i have a look in the browser i change into text then i select uh radio for example i still have those options or select i have those options okay and down below i'm going to aim it change event passing the data okay the only thing we're missing is to define that uuid version for function and let's have a look in the browser if i click add option right here i get this error uid v4 is not defined we need to scroll up right here and inside the import section we're going to write that import okay we need to import from uuid package which we're going to install right now we're going to import v4 function is uuid v4 now let's open the terminal i'm going to kill this i'm going to run npm install dash s uid hit enter on this okay this will install the uuid package we're going to start the server back and if we have a look right now in the browser click add option let's clear the terminal click option we see options are actually added whenever we click add question or delete question buttons we get the following errors in the console that's because we have not defined those functions let's go in the question editor component and down below i'm going to define those two functions for 8 question and delete question which finally should trigger emit events so let's add those functions right here and this one should emit ed question event and we need to pass the index of the current question plus one which means that whenever we click add right here it's going to create a new question on uh with the number three it's the next question should be right here basically the newly edited question okay just like this let's add delete question we need to emit delete question event and we need to pass the question which on which we try to delete basically if we go in the survey view we need to handle those cases because if you remember if we scroll up and have a look in the template in the question section we are listening change add question and delete question events okay so let's collapse the template scroll down below first of all we need to import that v4 as uidv for from uid package because we're going to need that right here okay and down below i'm going to add call create a function add question we accept those index which is passed from here and then i'm going to create new question object and give the following default values like the id in this case it's going to be uid but whenever we pass test that information to the back end the backend will generally save in the database as an id the default type will be text question empty description null we pass the data as an empty object and finally we need to put this in the correct place so i'm going to call modal value questions slice and the slice is very powerful function of array we're going to pass index right here the next argument is how many elements we want to delete i don't want to delete anything so i'm going to pass 0 right here and the next is uh what uh object i want to insert inside the array i'm going to pass a new question and just like this question will be added inside the questions array okay we can test this so far i'm going to just click add right here and down below new question was added okay now let's implement delete question so i'm going to create delete question function we accept the question which is passed from the question editor this one okay and right here we are passing basically props question we don't pass the actual modal object because we are what we hear is actually uh question uid or question id so in this case we have the question id so because we're going to delete the question finally based on its id okay how we're going to do this perfect so model questions we need to update our moodle value questions model value questions equals and we're going to call on existing module value questions a field here we're going to take out only those questions which does not have the given question id everything else should go inside the new questions okay so right here we write if the queue does not equal to the question okay now we can even improve this and right here question id doesn't equal to qid just like this or this one will be also enough whenever we save this and go in the browser i'm going to click delete on this and this is deleted we click delete and everything basically is deleted okay next thing is to implement change question whenever question changes so we need to create function question change right here we we accept question and that's also passed from the um question editor from here we accept right here updated question and here's the interesting thing we need to do something similar like we did for the questions we need to create new questions array but in this case i'm going to call modal value questions map and i'm going to map each question to its new corresponding value but first inside there i'm going to check i'm going to pass the callback of course and then i'm going to check if the each individual question id equals the given question id this means that this question basically the queue is about to be changed and in the new array modal value questions we need to return the given question but i don't want to just return the question um it can be done like this but to avoid any kind of like reference changes in the future i'm going to wrap this inside json stringify and jsonparse and down below i'm going to return the queue whatever it is so again if the question id doesn't equal to the queue id then we simply return whatever is inside the original module questions area right here otherwise we return the given question so i save this and now if i make any changes right there that's going to be affected it's going to be given to the parent as well so finally in the peer and survey view modal value questions will always be up to date and we can print this every time we make some changes we're gonna see that this is up-to-date data information we need that whenever we click the save button on the survey view we need to pass always up-to-date information to the backend now let's open phpstorm and generate survey controller and work on the backend side i'm going to bring up the terminal open new terminal and run php artisan make controller survey controller dash dash model equals survey api requests so right here we specify the controller name i specify also that i want this controller for the api and i wanted to generate request classes as well we're going to see that so the request classes as well as the controller uh has been successfully generated now let's go in the app http controllers and right here we see the survey controller if you go in the requests we see right here store survey request and update survey request i want to also generate a resource so i'm going to run php artisan make resource and i'm going to call this survey resource hit enter resource created successfully let's go in the up http resources folder and right here we see survey resource my survey has slug so when whatever i type inside the tattoo title the slug should be generated from the title so i'm going to install laravel sluggable package the first one so let's go down below we need to find composer require i'm going to grab this open the terminal and right here i'm going to run composer require okay the package has been installed let's now go in the controller survey controller and implement those methods right here okay let's implement these methods step by step first of all i'm going to implement index i'm going to accept right here a request class and i'm going to import that class a little bit later down below i'm going to get the current user from the request then i'm going to write return on the survey model i'm going to call where the user id field inside the database equals to the current user id and then i'm going to call paginate on that result because i want also to implement agination but finally because we created survey resources well i'm gonna wrap everything inside survey resource collection okay so this is basically all for the index and that's already working now let's scroll at the top and right here i'm gonna write use illuminate http request for this one as well as up http resources survey resource for this one okay let's implement store method first of all i'm going to get request validated data the star survey request is just an empty class we haven't implemented any rules right here we're going to do this later but now i'm going to already use request validated right here which basically will give me all the validated data i'm going to pass this into survey create which will create a make a record in the database and return a result i'm going to assign the returned result into a result variable and finally i'm going to return this result variable but i'm going to give it to the survey resource so creating an instance and passing to the passing the result right there all right let's also implement it let's move on on the second method which is show the show method basically is i think the simplest one but we need to add one additional check right here so as a simplest implementation of this will be just to return the given survey right here in a survey resource and that's it we already have resource but i'm going to add a check that the user who is basically trying to get the current survey has permission is the owner of the survey okay so for this i'm gonna first of all add a request parameter in the method then i'm gonna take out the request user and i'm going to write a check statement if statement right here if the request user id does not equal to the survey user id this means that the authorized user is different rather than the owner of the survey so we basically need to abort the following if inside the if statement and just return 403 unauthorized action so basically the current user doesn't have permission to get the current survey okay otherwise we return the survey and that's basically it let's implement the next one which is update okay i'm going to get the request validated data i'm going to pass it to the survey update function which will basically make an update in the database and finally i'm going to return a survey with new resource and finally let's implement destroy okay first let's add request parameter in the arguments then i'm going to get the current user from the request then i'm going to make an if statement to check if the current user has permission to delete the current survey if not we're going to abort with status code 403 with unauthorized action message otherwise i'm going to call delete on the survey and finally i'm going to return a response with an empty content but the status code will be 204 which is basically a common status code for for deletion now since our survey controller is ready we can go in the store survey request and implement rules and everything right here okay first of all inside the authorized method i'm going to return always true okay otherwise my request will be simply rejected then i'm going to create method right here which is prepare for validation basically i override the parent method and inside the attributes for the request i'm going to add user id which will be the current user id okay then let's go down below and implement rules right here i'm going to add rules for title user id status description and expire date and then let's specify rules for each individual attribute the title needs to be required string with maximum 1 000. user id needs to exist in the user's table id column status needs to be required in boolean description will be nullable in string expired date will be nullable date and the value should be after tomorrow okay we have our store survey request ready now since we already implemented survey controller and store survey request we can go in the survey recourse resource because we are already using that in the controller okay from here i'm gonna return an array instead of calling peer into array and let's specify each individual attributes i want to return i want to return id which is going to be this id title i want to return slug status description created it updated it expire date and questions empty array at the moment i'm gonna right here uh put right here an empty array but of course we're gonna get the questions and return those questions later as for the status you can see the if the status doesn't equal draft it it means that the status will be boolean true otherwise it's going to be boolean false now let's open survey model and we need to make some changes right here as well now let's add right here a fillable array and we need to specify all the attributes that should be fillable and filled by fillable i mean that in the survey controller whenever we create survey we specify right here request validates all the data and laravel automatically fills the survey properties based on the data and we need to specify right here so the available properties are user id title slug status description and expired date next we installed laravel sluggable and we need to use it right here we basically need to configure our survey model to take the title convert into slug and save it into slug field in the database so for this i'm going to use has slug trait which we will import in a few seconds and down below i'm going to create get slug options function okay and down below i'm going to return slug options create generate slugs from title save slugs to slug and at the top let's import those two classes trades has slug and slug options last thing to do on the back inside is to go in the api php inside which we have all our roads and down below we need to define a resource road for the survey so and the class will be basically survey controller up http controllers survey controller and this resource basically indicates that i have uh at least five endpoints on the following resource like get all surveys get single survey with slash and the survey id update delete survey all that crowd operations is supported by specifying road resource all right let's now go on the vue.js side and try to create survey in the database on our form we already have method save survey we need to scroll down below and create that function right here okay at the bottom we need to create the serv save survey function so i'm going to call dispatch with the save survey action on the store pass the model survey and listen on the callback the save survey action doesn't exist yet but we're going to create it soon in the callback i get the data and down below i'm going to call rotor push i need to navigate user on the survey view page basically if the user is just creating a survey the current road name will be survey create so the user will stay on the same page but the road will be different okay so survey view and inside the params i'm going to pass the received user received surveys id okay that's how it is let's scroll at the top and we need to import the use rotor and create router right here all right the next thing to do is to implement that save survey so let's go in the store file and implement this right here okay in the store i'm going to define save survey we accept survey right here i'm going to define a response variable and down below i'm going to check if the survey has id it means that we are updating survey and we need to make a put request right here otherwise we need to make post requests because we're creating a new survey and in the then of the update we're going to call update survey mutation we're commenting this the mutation doesn't exist yet we're going to create it soon however if we're creating new survey i'm going to call and we need to return the result in any case from the callback so however if we are creating new survey we're going to commit save survey and return the result from here and we have a response variable which needs to be returned in all cases from the save survey okay let's define right here save survey mutation in update survey in safe survey we're going to assign state service equals to structure the existing state surveys and aid survey data this is the current survey data okay in the update survey the state service equals i'm going to map each individual survey into a new object and check if the each individual survey equals the received survey id then we return the survey and rate survey right here otherwise we return s but the thing is that right here instead of survey you should return survey dot data because survey in this case is a response received from the axios and we need to take out the data and right here i guess we need as well survey dot data id we're going to test this and if we have some bug we're going to fix that now let's open the browser let's actually go back and try to create a new survey i'm going to also have a look in the network i'm going to fill up the form with some dummy data and let's hit save all right let's have a look we got the response 201 from the backend which means that the survey has been successfully created which is actually awesome now let's see why we were not redirected well actually we are redirected to the uh current page as we have implemented okay let's try to create one additional survey whenever we create a survey we need to check if every field is successfully set for example slug so let's call this lorem ipsum description let's specify some date as well and checkbox let's hit the save button and have a look in the response we have the data inside the data we have uh title as well as this log in the expired date and description everything basically looks correct however if i create create new survey with the same title let's open this page again with the same title then the slug will be different the slide will be lorem ipsum 1 and that's what this sluggable package basically does and that's exactly what we want now let's add image column to the surveys table i'm going to open the terminal and generate migration php artisan make migration add image column to service table and hit enter on that let's go in the database migrations and right here we see this newly generated immigration okay let's add right here a new column on the table i'm going to add string column and the column name will be image the length will be 255. okay let's scroll down below and create down as well on table i'm going to call drop drop column on image okay looks good now let's run php artisan migrate okay it created that column in the database perfect now let's go in the survey controller and implement attaching that image let's go on the update first or let's go actually on the create first and we need to adjust the rules as well how we're going to do that but let's actually go on the front-end side open survey view and have a look at our input type let me close zoom in okay nice here we have that that's the button input type file it doesn't have v model or anything but we cannot actually add v model to input type files we need to add a change event listener um on image on image choose for example and then we need to get that image and save it in a variable and then send it to the back end or we can also implement um to preview that image now let's scroll down below and implement that function on file choose i'm going to do this right before the 8th question right here function on image choose okay perfect now on immediate we're going to get get accept an event right here then from the even target files i'm going to get the first one and that's that's going to be my file i want to send to the back end but i'm going to do the file preview as well image preview as well so for this i'm going to create file reader and on that reader i'm going to call a method read as data url and pass the file whenever this will read the image it will call on load callback which is a function and right here i'm going to get the reader result which will be the base64 string as a as a url to basically display and i'm going to assign it to the modal value image remember modal value image is the variable which is basically used to display in the component in the template okay but i'm going to make some changes right here i'm going to use that modal value image to send it to the back end as a base64 string and i'm going to use another url like image url to display so image will be used to send the image to the backend image url will be to display it right here okay now let's go at the place where we have that image right here and i'm going to change that instead of using image right here i'm going to use image underscore url to display okay looks good let's actually save this and have a look in the browser we should be able to see preview okay here it is i'm going to click on change let's choose one image here it is we have the image preview looks awesome choose another image we have that we haven't yet implemented to fetch the surveys but whenever we do that we need to return inside image url variable the the actual image okay now as far as we know that we need to send image from the front and to the back end let's go on the back inside and right here i'm going to add image to be it must be string sometimes it can be empty so we need to allow nullable as well okay perfect let's go in the survey controller in the store and right here take that received image consider it to be nice base64 string and we need to save it as a file let's see the actual data which is sent i'm going to call this test and down below click on save and in the survey in the payload we see we send image as well as image url we need to delete image url because that should be only used for display purposes this one is what we need to send and this is how this looks like data that this page 64 string basically but we need to remove the following uh part and then the rest of the thing will be something we need to handle on the back inside okay first on the front side again let's go in the store slash index and this is our temporary area which we won't need soon down below we have this save survey and i'm going to call delete on that survey we're going to delete image underscore url okay save this and now if i upload an image give it title and save on the request we won't have that image url which is exactly what we want okay let's go on the backend and work right here i'm going to take this line and split it into two lines first of all i'm going to take the request validated data and save in a variable called it data and pass the data right here in the survey create i'm going to also rename this result into a survey and right here i'm going to pass survey okay this works fine i just made small changes now i need to check if my data contains image right there because the image is not actually required and technically it can be null so if my null or not presented in the data at all if my data contains an image we're gonna take that image and say on a local file system okay so for this i'm gonna create a new method called save image in this controller it's going to be private or protected method i'm going to pass the data image which is going to be the base64 string this one the whole thing and it will basically do the all the necessary things we're going to create that function soon and then finally it's going to return relative path i'm going to take that relative path and assign into data back into data image and finally whenever we put the whole data inside the surveys create it's going to take that image and save in the database but we need to make sure that in survey we add somewhere right here for example image instead of the fillable otherwise this image will be lost okay now let's create this function hit alt enter add method down below let's implement this right here i'm going to write an if-else statement and first of all test if my image is a valid base64 string and inside the if i'm going to use a regex and call the method pre-match inside the prick match we're going to pass the following regex pattern the string needs to start with the data column image then there should be slash there should be some sort of alphanumeric alpha basically uh characters more than one and then semicolon base64 in comma the rest of the things we we basically don't care it will be encoded base 64 string and i'm going to run this regex on an image variable and finally we're going to save the matched results in a type variable okay so it's going to basically test if my string starts with this pattern which is necessary to do and the next thing is to in the else basically we just need to throw an exception at the moment we just throw an exception but in the future we can improve that and return a nice user error that like this is not a valid url or something like this okay now let's take out the base64 encoded text without the mime type so we need to take everything after the comma okay so for this i'm going to call substring method in an image and then right here i'm going to specify the position of the comma plus one so basically everything after the comma we just need to take it save it in a image and that that's what we want next is to get the file extension and that's gonna be matched results first because this one is uh inside the group inside the parentheses parenthesis then we just need to take the first one so that's going to be the type that's going to be jpg or png or whatever is the image extension in this case it's going to be png this one okay the next thing is to check if the type is a valid image so we just check simply if the type is in the following array and if it's not we just again throw an exception and down below we need to prepare our image variable which is already encoded string this one and first of all if there are some white spaces we replace them with the plus sign next we call the code on that and finally our image basically is ready we just need to check once again if the image is false we throw an exception okay and down below the if statement we prepare the path where we need to save our image that's going to be the the directory will be basically um under public so under public and i'm going to create the that images folder and we're going to save everything right there okay so the the images folder is already created i created it manually but if the director doesn't exist it's going to create it also i can actually delete that one let's actually delete this okay now right here we take uh the we we just create a variable for directory then i'm going to create the file name that's going to be some random string and the extension will be the extension which we detected the image has then i'm going to create two variables one for absolute path second for relative path and you'll see why i need both variables the absolute path is used to check if the path exists the directory exists the images if it doesn't exist we just create the directory okay and relative path i need to return from this method that's going to be whatever will be saved in the database okay finally i call file put contents on relative path i can call on absolute path as well both of them will work the relative works simply because the entry script of the application index php is inside the public and relative path will simply create a file inside images random string dot png right here inside the public okay i can use right here relative or absolute both will work and then i can return a relative path from here and finally let's scroll at the top and i need to basically i'm using two classes str and file and i need to use them at the top so right here i'm gonna write use the file illuminate support facades file and support str okay so now if we just try to upload a file image it should work so let's choose like plural for example and we have the test and the the expiry date inactive can be now so click on save and let's see okay create it looks like it was created we don't get where it is we don't get an image or image url because we don't have the field in the resources but let's go on the file system and see the images folder has been created and right there we have this image here it is our laravel image we can check in the database as well in the php my admin if the file was actually successfully saved let's go right here click on surveys and here is our image okay this means that the our script works perfectly by the way i'm gonna um make this field image field we made this mandatory uh while in immigration we need to make it actually nullible so if we go in the migrations because sometimes it can be empty right so right here um at the top so i'm gonna give it to be nullable and i also want it to be after uh user id field okay it should be right here before the title so let's open and run phprt zone make not make migrate rollback and then migrate once again okay now if i just reload phpmyadmin we see image url right here okay i can delete that survey or leave it uh and go again and create one survey test two save that and have a look in the database we have the image populated in the file system let's go in the public right here we have now two images okay it looks perfect now we need to do something similar on a survey update okay we implemented on the store method but let's go down below and right here we need to make some changes as well okay here again i'm going to split this line into two lines first take out the request validated data and save it in a data variable and then call update with the data on the survey and right here then let's write an if statement if the image exists inside the data we take that and we do basically the same thing we call the save image passing the data get the relative path and then we assign relative path into data image now we already have image inside the fillable of the survey so that's gonna work simply uh the last thing we need to do here is that if we're updating a survey and it already has an old version of image we need to delete delete that right so i'm going to write here if there's an old image if survey image exists so we create an absolute path with a public path method and then i'm going to call file delete on that absolute path okay the rest of the things will simply work now let's do like this i'm going to open the public folder right here we have two images and this one basically the second one has already an image we don't uh preview it right now but it has we created right here in the database okay now if i just change it into like vs code for example and hit on save let's see on the file system okay the old image was not was not saved okay we have two laravel uh okay it wasn't saved for some reason i mean the image was not deleted let's try once again choose an image save okay it always create new image it doesn't delete this one we can have a look what's the actual value of the survey image so we can dump this right here and click on let's actually choose another one click on save i think i know the reason i think i know the reason the reason is that this if is not satisfied at all because in the let me make sure it collapses the left side in the update survey request we did not have anything at all we don't have any rules or anything okay let's add right here title image user id status description expired date and questions to an array we're going to implement questions a little bit later let's focus on the image first also we need to go on the authorized method and delete this one and we need to add right here check that the user who is trying to basically update the survey is the owner of the survey in the controller on the update we get the survey as a modal variable right here okay we want to access the same survey variable right here in the authorize so for this i'm going to run this road and survey the param name which is the survey so i get the model right here and now i need to check if this user id and this user is the authorized user that this user id doesn't equal to the survey user id this means that i am not the owner of the current survey and simply return false i should not be able to update the survey otherwise we return true okay so i think we did everything right here we just need to make this image to be nullable as well and string and now if we just try to update now let's choose another one i chose another one because this one was already selected and when you just we selected it it didn't do anything okay so let's choose lar for example and before i say if we go in the file system again and see we have five images right now okay so whenever we save this we still need to have five okay we we don't have uh the again image was not was not deleted let's have a look so data image exists let's actually print what's the survey it's the survey image let's print that hit on save oh we don't get that do we get anything right here like something is weird going on i think i know what's going on we are basically always calling post created that's the issue we we never call update that's the thing we always create new survey okay this is something we need to handle on the front front-end side but on the back inside i think everything is everything is correctly done so now let's jump on the front side because we we had an issue on there just one last thing i want to do here is that those images are in the public folder if i comment and push everything those will be committed and pushed which is something i don't want so i'm going to create git ignore file inside the images and i'm going to ignore everything except the git ignore file itself okay whenever i run a comment or whenever i run hit status those images won't be displayed in the status okay i'm going to call git add it's status and i don't have those images everything what i see right here must be committed and pushed okay the problem in this case is right here in this place because we just tried to get the survey from the surveys area but now that's not going to work we need to make an http request to get the current survey so whenever i reload the page it should make an http request and display the survey information right here we actually have an error right here because the survey with id 7 does not exist in the store state surveys array okay that's the thing so let's change this place i'm going to delete this and i'm going to actually write on store i'm going to call dispatch i'm going to call the action get survey and i'm going to pass right here wrote params id it's going to make requests we need to implement that action it's going to make requests and save that information in the store and then we're going to get that information from the store again so let's go in the store and right here in the actions i'm going to create that git survey we're gonna take out comment rate here we're gonna get id right here and let's make an http request before i make an http request i need to define right here a state for the current survey the current survey is basically this array which is opened at the moment okay so let's create current survey variable right here it's going to be an object and i'm going to add right here two properties one is loading so if the current survey is in the loading state second is data the data will be an object and that's the actual content of this survey okay in the action first i'm going to start the loading indicator so basically i set the current survey loading to be true and i'm going to use that in the component to show some loading text or loading indicator css animation okay so this is the point we make in http request okay then we make an http request we pass the survey id right here inside then we get the response the result and i'm going to set the response data to be the current survey this this is a mutation which we need to create right now and finally we're going to return this result right here i'm going to handle the case that whenever we get the response the survey loading should be stopped okay we start the survey loading make an http request get the response stop the survey loading okay and finally we need to handle the catch scenario as well and we also disable the loading and we throw an error whatever comes right here okay now we need to create two mutations set current survey loading and set current survey let's scroll down below in the mutation section and let's define here those two mutations set current survey loading we accept the state in loading and i'm going to define the second one which is the set current survey and in the loading which we just simply take the loading variable and assign it to the current survey loading and in the set current survey we just take the survey and take out the data from that and we're going to see why we do that because whenever a response is received from the backend it is wrapped inside the data okay we basically take data a few times like two times one once we take the data right here and this one is the response and actual data is dot data and in this case dot data is everything everything and down below in the mutation we take the survey.data and in this case the data will be this thing okay this is this is how we do now we need to go in the survey view and take out the current survey and use it right here so we make request to get survey it's going to update the current survey variable and now we need to uh take the current survey here so here basically i need to watch the current survey from the store when whenever current survey changes i need to update the local model variable okay so for this i'm going to call a watch function which i will import soon from the view okay inside the watch we pass a callback and we simply watch storestatesurveycurrentsurvey.data okay this is an actual data and we're watching that okay the watch accepts the second argument right here which is a callback whenever this one changes then we this callback will be called and we have new value and old value in this case we are interested in a new value so i'm going to take the new value and assign it into modal value but i'm not going to simply assign it just like that i want to first of all call json stringify and jsonparse to avoid any reference changes in the future and i want to destructure that however the status basically which is going to be returned from there is either draft or active so we need status to be boolean so in this case i check if the status doesn't equal draft then the status will be an active okay and just like this we have the current survey data assigned into a model okay let's scroll up and import that watch right here in the survey and let's actually let's actually go in the browser and have a look so whenever we try to access survey with id2 for example it makes a request let's have a look it made a get request the data was received and the form was populated we have active we have test two let's open the first one uh sorry first one we have test uh how many surveys do we have here so we have like uh seven right so test three test four test five let's try the seventh one which is gonna be test two title yeah title is always test two okay slug slug is actually different but the title is always test two okay if we just try to update now this test to updated for example and hit on save this one makes now put request okay so now let's have a look we received a title to be tested updated if i just reload the page i see test to update it right here okay and if i just choose an image hit on save uh if i just have a look in the in the store in the file system let's have a look let's go in the public okay we have like um seven seven images okay if i just choose another one hit on save here let's have a look now look at this we still have seven images one was deleted second one was created like in this case we do update properly okay let's actually open um survey resource and from here simply return an image to be url that should be illuminate support facets to and we need to pass this image right here okay and let's add an additional if statement right here if the image exists let's return this as an http url otherwise we return now let's save this and reload the page click on that go in the preview and we see right here image actually i want to return image underscore url because that's how we are using on the front hand side reload the page and now we see that image displayed right here because image url was successfully returned now let's change this into laravel hit on save that was updated we lost the image right here but if i reload it we have this laravel so why did we lost that image we need to find out let's try to change this once again hit on save let's see what data we get we get the image url but why it is actually lost for this let's go in the survey view and let's actually print the whole model i think something is wrong with the model the model does not have the image right here it has image it doesn't have image underscore url let's specify it to be null we don't actually hear image anymore so i'm going to remove this let's see maybe the issue is that save now the images image url is still lost okay let's actually print the image not only the image but the whole model okay so model print right here and have a look we have image to be the chosen one okay we have image url as well now if i just reload the page we have image url right here let's change into laravel hit on save and now image url is lost well strange i think i know the reason for that as well so if we go in the store whenever we update the survey save or update it doesn't really matter the current survey is not updated the survey which is displayed right here okay this is what we need to change so whenever we commit update survey or safe survey i think we don't really need that update survey in safe survey because it was making changes in the surveys area okay now we don't hear that so i'm gonna simply delete those two mutations and simply we're gonna call set current survey in both cases and we pass the result date let's save this and have a look we have laravel image change into angular hit on save and here we have here we have everything what we expect so far let's change this into ujs we don't have angular right now and let's have a look in the back end as well right here we still have seven images so we deleted we re-uploaded image many times but the image is now deleted whenever we just upload a new one looks awesome now whenever we reload the page we see that the title is create a survey and then it appears also the form is empty and then the laravel image and the text appear that's because there the request needs some time right to fetch the data and in the store we created that loading flag okay and let's actually use that flag to write some loading text in the component okay so for this right here i'm going to write a const survey loading flag which is going to be computed property and that's going to watch on the store state current survey current survey dot loading okay and let's use these computed right here and let me actually print that right here in the template so reload the page it's true then it turns into false so right here i'm going to create a div with the if and if the survey loading if the survey is in loading state i'm going to write text loading and let's give it a class of flex and justify center let's reload the page we see loading text see that if we just go in the network and change into like uh slow 3g and reload we see it's very slow very slow let's turn into a fast 3g reload the page where is that please come on hey okay i'm gonna skip that okay you see that uh loading right so instead of um like displaying the form i want to hide the form so inside the vls i want to show that form so we see loading and then form appears the same thing for the title we see create a survey right here which i don't want to see okay that's ugly instead of module id right here i'm going to use road perms id we have wrote perms id we are using that whenever inside wrote there is perms id we know that it's it should be an update okay so road dot params.id we show module title model title sometimes might be empty but instead of create a survey better to show an empty string then create survey okay and this is how we do the loading and inside the instead of loading text of course we can write some create some css indicators like low spinners and so on now let's start working on the delete of the survey on the survey view next to the create survey or next to the title i'm going to put a button right here okay the button should only be displayed if the road perms id exists it means that we should not show the button on survey creation okay this view this component is used on survey creation as well you know so if we go now in the browser we see that delete survey button okay let's actually add a trash icon so we add the click event listener as well as the trash icon right here let's save this the trash icon is huge so let's add the classes right here and save it and here it is okay nice so whenever we click that now we don't have that delete survey function created so let's actually copy the name scroll down below and create that okay let's define a function i'm going to write an if statement and ask basically user to confirm if he really wants to delete the survey okay just deleting a resource whenever someone clicks on button immediately is not a good idea maybe someone mistakenly clicked on the button okay so i'm going to show a browser's default confirmation right here are you sure you really want to delete the survey something like this if user confirmed that then i'm going to call store dispatch delete survey so i'm calling this delete survey action it doesn't exist in the store we're going to create it i'm going to pass the modal value id that's the survey id we want to delete and let's listen uh whenever this happens so whenever we get a response from the server that is deleted inside then i'm going to push the road i'm going to change the road into surveys page basically we redirect user to the survey list page okay i save this let's go in the store and create the delete survey that action is the simplest action we create that the first argument is the object we don't want to destructure i'm not going to take comment or anything i just get the id and make an http request on axios client to delete that survey okay that's basically all if we go in the browser and just hit on delete survey we get the confirmation click okay okay we made an http request this status code is 204 it was successfully deleted however if we go in the phpmyadmin as well and reload we only see like we see seven okay let's delete one more like the first one okay click on delete okay reload the page okay yeah it was successfully deleted now whenever we delete that we need to delete the image as well from the local file system okay right here the images are not deleted so let's open survey controller and find the destroy method and right here we need to delete so basically if we go up right here if the there's an old image just delete it we need to copy this and put this right here before the delete or after we can do this after the deletive till it successfully happens okay now there are like eight eight images if we just open the second survey and hit on delete let's have a look on the file system yeah the image was actually deleted now we need to fetch the surveys from the database for this i'm going to open the vs code and go in the store file and we have right here tmp service which is displayed right here so we need to delete those tmp surveys and we need to basically fetch the surveys from the database i have deleted all the existing surveys and created new ones with some actual images and some close to real content okay so i'm going to actually delete those this tmp surveys and remove it from here as well so we have surveys i'm going to convert these surveys into an object which will have loading rate here to be false by default and the data will be in array okay now we need to open surveys dot view file and right here we need to make an http request to get surveys so for this i'm going to actually uh call on store i'm going to call dispatch and call the action get service we don't have that get service right now so let's go in the store and right here we have the get survey we have save survey delete survey and right here i'm going to create get surveys we get comment right here and let's make an http request right here first we're going to start the loading of the surveys so i'm going to call the mutation set surveys loading and set to true we're going to create that mutation then i'm going to make an http request on the slash survey endpoint in the callback i'm gonna stop the loading and i'm gonna take the receive data res data and call the mutation set surveys and pass it there okay now let's scroll down below and create that search set surveys loading mutation just like we have said current survey loading i'm going to duplicate this and call this set surveys loading this will be surveys loading equals loading and just like we have said current survey we need to create another mutation set surveys we get the data right here and inside the surveys data we assign this data actually we're going to have data inside so i'm going to call this surveys and then right here we're going to have surveys.data okay let's save this we're making get service requests from here so let's go in the browser and have a look okay reload the page we have an error something is going on unauthorized so we are not actually authorized okay now i'm going to clear my session storage and reload the page and now login once again now let's go on the surveys page and let's see what we have right here missing required problem id okay the request was made we got the data but we have an issue okay let's have a look at what we have in the store in the mutation so right here i'm going to put debugger and have a look so we have surveys we have data we need to take the data and assign it into service data looks good however the thing is that in the service component we expect surveys but instead we need to return dot data that's the thing we made changes in the store right here okay if we save this and reload the page let's continue here we have so we have all those surveys images are missing i think because in the surveys we are still using the image not image url so let's collapse the header right here we are iterating our surveys right here we need to use image underscore url if we save this and have a look that looks awesome so we have all these surveys okay now i'm going to actually create new component for survey list item and move each individual item right there so let's go in the components and right here i'm going to create survey list item.view let's generate the boilerplate code and work right here i'm going to collapse the left side okay first of all let's actually grab everything from here and paste everything here and in the surface view i'm going to use survey list item component which was automatically imported by vs code okay we need to start iterating right here v4 so let's copy the v4 section here we have v4 as well as the key i'm going to take this and here we have v4n key we can put this on a single line and we need to pass a survey object as a prop so here is our survey let's actually show this on separate lines just like this okay now in the survey list item uh i need to remove the debugger from from the mutation from here okay all right now in the survey list item let's scroll down below i'm going to change the script to his composition api and right here i'm going to define props and we're going to have only one prop which is going to be survey to be object okay and i want to take the received survey and save it in a variable called survey looks awesome i'm going to also define emits define oops define emit we're going to define delete and edit whenever delete or edit buttons are clicked we are going to aim it to the parent okay now let's find those buttons this is the delete button and instead of calling delete survey i'm going to call emit on delete and we're going to pass the current survey let's scroll up this is the delete button um on delete we base on edit basically we just redirect user so we don't actually need to do anything regarding edit so we can even remove this from here save that go in the service component and add right here delete okay whenever delete is called on this component we need to call delete survey okay right here we show the confirmation that looks awesome let's have a look we have an error undetermined string constant oops where t's necessarily cite item let's remove this all right reload the page we have everything if i just click delete uh edit uh it works fine the server is open if i click delete it shows this confirmation we can implement delete um in the surveys right here just like we did for the uh from the survey view so we just need to call store dispatch uh delete survey and we need to pass survey dot id okay let's have a look let me actually create new one i don't want to delete existing ones test let's choose image hit on save that was saved go in the surveys list and let's go down below we have the node.js right here let's open the network and click on delete okay on that the request was made survey was deleted but this survey still stays right here we need to reload the list of the surveys okay we can do this right here whenever the survey is deleted in the callback we're going to call store dispatch get surveys okay let's create one more survey i'm going to create without image in this case let's oops i need to go in the list and let's call delete okay it was deleted service we are fetched and we have updated list right here which looks awesome we have successfully implemented survey creation update as well as the delete now we need to focus on creating questions first of all let's go on the backend side and we need to work in the survey controller but let's understand whenever we send a request what type of data we send so let's create a new survey and in this case we need to add questions like question one for example i'm going to hit on save right here and let's see what data we sent in the payload we have questions so in the questions we have each question has basically data description id question everything basically is successfully sent from the front end so if i add one more question that's gonna be sent right here but we don't handle those questions on the backend side so let's go in the survey controller and at the top whenever we basically uh create new um new survey in the store action we need to handle the saving of our questions right here actually we need to do this right here down below so here's the place where we need to create new questions first of all i'm gonna get the questions data from the data and start iterating over those questions each question needs to have survey id so i'm going to take the just created survey id and give it to the question and then i'm going to save this question but i need to apply validations on each individual question as well i'm going to create a separate method called create question i'm going to pass that question object and this purpose is simply to create a question in database okay so in the store we did everything now we need to create that create question method okay down below we can create private or protected method and let's work right here so here we need to check if the data contains data right there so this this data is whatever we send as an object right here so this might contain options area for example if the question type is select or checkbox or radio okay so if the data contains data which is object in javascript but it's going to be array in the php side so we need to encode that and save it as json string so we need to call json encode on that data and assign it back to the data okay now we need to do that because we cannot save an array in the database so we need to save this as json now we're going to create validator right here i'm going to create new validator and pass data and let's define rules the question needs to be required and string the type needs to be required and we have basically five types at the moment so the type needs to be one of the following types so i'm gonna use rule in in this case and pass the available types but i don't want to just type right here text select etc so i want to create i can create enum but because we are doing this on php 8.0 and if you're just following this tutorial on 8.0 you're going to have an issues because you have to update your php version to 8.1 if you are doing this on php 8.1 you can just have a implement this using anims in the validator of um like if we just open laravel uh validators you can see right here that this one supports anim okay and i'm rule and you can do that but in my case i'm gonna just pass right here an array rule in and i'm going to open survey dot php model and i'm going to create a constant variables right here for different types like type tech it's going to be text and just like this i'm going to duplicate and create all types okay so here i copied and pasted all the types text text area select radio and checkbox now if you go in the survey controller i'm going to use those types right here okay okay the next field is description which can be nullable and string the next field is data which must present it simply it must be simply presented in the data and and i do this because whenever i just uh put the validated data inside the question create they should not be skipped okay the next one the last one is survey id which must exist in the survey id field okay and finally i'm going to call survey question create i'm going to pass the validator validated data and return just created question we have used right here validator class rule class and survey question so we have to import those a scroll at the top and right here i'm going to use all those classes okay we have implemented saving questions now let's go in the browser and reload the page and let's add questions well this is an update we didn't implement this on update we did this on create so let's create new one i'm going to call this test two and let's add two questions question one which is gonna be text and this one's gonna be question two which is gonna be select and let's add option one let's save this okay we have an error we didn't do something correctly undefined array key questions okay it seems like the getting the questions on survey controller line 48 did not work successfully and that's probably because the survey store request doesn't have questions in the rules and i'm right so right here we need to specify questions to be array let's save this and make request once again we still have the same error now the issue is that the question is not added into fillable that's also correct we need to open a survey question right here and we need to add billable and add right here question data type survey id and what's next let's see what information we pass data description id question type we have question data type survey id and we need description i think we passed everything now let's make request once again and have a look i think now it was successfully saved we got the response back now we need to have a look in the database so if i just reload this and he'll go in the survey questions yeah let's go in the survey questions okay i actually have already questions for those other surveys which i created manually but we are interested on this one question one and question two on question one we have empty array however on question two which has type of select this is what we just created it has the options and this one thing it has option one as well so it looks like everything worked fine now we need to return those questions on the front-end side so let's go in the survey and well basically we need to have a look in the survey resource right here when we whenever we call the um to array instead of passing empty array right here we're going to return these questions but i think this will not work because our survey does not have a relationship also our question doesn't have relationship to the survey now let's do this here i'm going to create a public function and i'm going to call this questions and we're going to return this as many survey question class and that's it and in the survey question we need to create public function survey and we're going to return this belongs to survey oops that should be survey column column class that's how it should be now whenever we access surveys it's going to return an airy let's have a look in the browser and well this should return questions for every survey basically not only when we create so if we go in the surveys and just click let's open any like we created the test two so let's edit this one we should get questions right there so let's expand this uh the questions is empty array why is this because that one doesn't have any questions i think let's open this one okay i think the reason is that we have pagination right here let's open the other one which i'm sure it has questions like like this one for example okay let's go and here we have the questions okay we got all the questions so returning questions actually works fine that's the same survey we had inside the tmp surveys but the data is string and the create that is that's thing and i i want to create now survey question resource okay and return this i'm going to bring up the terminal and call php artisan make resource and i'm going to call this survey question resource hit enter let's collapse the terminal now let's go in the http resources survey question resource and right here let's implement to array okay we need to return id type question description and the data but the data should be uh json decoded thing okay so let's wrap this inside string and we're going to return these following fields as for the data let's just return data is json decode these data now we need to use that survey question resource in the survey resource so instead of just returning these i'm going to call survey question resource collection and pass these questions now let's save this and reload the page and see what we get so we get data as an object we get description id question and type let's actually have a look in the survey we created now let me just zoom out slightly okay i think we don't we don't have this right now but if we go in the survey controller and find the index and increase the pagination to be like 50 for example and reload the page we should be able to see this test to with the id 61 which is this one and now we should have our given questions like two question type text in the question one type select with option single option which is option one so and down below we also have those options populated this looks awesome so this shows that we successfully implemented creating questions however we need to also uh implement the updating of the questions okay looks looks fine so we have also implemented getting the questions properly now let's go in the survey controller find the update method and implement updating questions right here okay after the survey is successfully updated we need to get the ids of existing questions as a plain array then we need to get the ids of the past questions the questions which are in the request of the new questions then we're going to find questions which needs to be deleted and we're going to do this by array difference so from these ids into these ideas we're going to see everything then we're going to find questions which we need to add then we need to delete those questions then we need to create new questions and finally we need to update existing questions let's start step by step so right here to get the existing ideas i'm going to call survey questions i'm going to call the planck method on this questions collection which will return a collection of the ids and then i'm going to call to array finally the existing ids will be just a plain array of ids of existing questions next i'm going to get the data questions id as a normal plain area of ids okay i'm going to use these array array helper down below i'm going to find the questions which i need to delete and i'm going to do this using array diff with from existing questions the to the new ones okay so down below i'm going to find the questions which i need to add so these are the new ideas if the new ideas contain for example one two and three and the existing ids contain for example the new ideas basically might contain some uids because for the questions we are passing random uid if there are some uids which does not present in the existing ideas that of course these are the questions which we need to add okay down below we need to just simply delete the to delete ids and that's going to be the plain area of ids and just like that we delete down below we need to create new questions and this is pretty much similar what we did for the create of the survey we iterate over data questions and we're going to check one one additional thing uh compared to the creating of the survey let's scroll up and have a look to remember this so right here we have this create question just one additional thing we do here is that we need to check if the question id is in the to add area because that might be the question which we need to update not delete okay and right here we have that we assign the survey id and then finally we're going to call create question and pass the question object which will simply create question in the database now let's see the questions we need to update i'm going to create a map of existing questions where the key is the id finally the question map will be like id corresponds to an actual object what we received in the request then i'm going to start iterating over the database questions then i'm going to check if the question id the database question id exists inside the question map this means that this is the question we need to update okay the database question id was presented in the request so the question was not deleted uh on the user interface so we have still that question and i'm going to call update question method which doesn't exist yet but we're going to create that soon i'm going to pass the question model and i'm going to pass that questions map question id right here okay and just like that we have implemented everything what we need we need to scroll up and import that array helper right here illuminate support array now let's go on the front hand side and see how this will work actually let's find the where it is the update survey request and if we don't have questions right here we have it so we don't need to do anything right here now let's actually modify modify this and call this updated updated and hit on save okay we have an error let's have a look survey question update question doesn't exist obviously we have not implemented this method update question i'm going to hit alt and enter add method down below and let's implement this okay i'm going to define that the question is basically an instance of survey question and i'm going to call this data here we need to check again if the data is presented inside the data then we need to encode that and sign back then we create a gain validator on the validator we define id must exist in the survey question id column then we define questions and type needs to be one of those types down below we define description to be nullable string and data must be presented in the object okay down below we just call update with the validator updated okay let's save this and have a look in the browser let's hit save right here we got successful response if we have a look in the questions the first one has updated right there so if i just reload the page i see the question one is updated let's actually add few more options like two three and four let's hit save it was successfully saved let's reload the page scroll down below we have those options let's actually change this type into radio and save reload the page and still we have radio we have successfully implementing a saving of questions which which was the most of the things about our application let's add some description as well reload the page and here we see the description it would be nice to show the notification whenever i hit save let's show a notification that the survey was successfully updated now let's implement the notification i'm going to open store and inside the store i'm going to define a new state for the notification for example right here notification it's going to have two properties show which by default will be false and message the message we need to display and that's going to be now now i'm going to create new component and i'm going to do this in the components area i'm going to call this notification dot view right here let's define the boilerplate code and i'm going to use the composition api so i'm going to find setup right here i'm going to import computed from view then i'm going to use the store from ux and create that store and finally i'm going to create constant notification which is going to be the computed store state notification okay just like that we have the notification and we can print or use that in the template let's define right here a div which will only be displayed if the notification show is true we're going to add classes right here we're going to display the notification message inside the div and in terms of classes we're going to need it to be fixed and it should be always at the bottom left corner of the screen it's going to have a width of 300 pixel left for bottom for some padding horizontal vertical text white and i'm going to also add right here animated fade in down class this should give us nice fading down animation which i'm going to create that class doesn't exist in tile1 and i'm going to create that but besides that i'm going to add right here a class as a computed as a view property bound property and i'm going to check basically if the notification type is success then i'm going to give it background emerald 500 otherwise i'm going to give it background red 500 okay so we need to define the type on the notification as well okay and just like this we have the notification component ready let's go in the view weeks and add right here type as well which is going to be null by default and now i'm going to go in the default layout and use that notification right here notification okay so the notification was automatically imported and just like this we we have i think it said in the component so we have everything properly set up okay if i just go in the index and change this show into true and have a look in the browser what happens so we see right here red so this means that the notification actually was successfully created but in this case because the type is not success it shows it gives the following class so if i just define type to be success and the message to be something we save this and have a look in the browser we see that notification okay let's implement displaying the identification properly so i'm going to create a mutation for that so down below i'm going to create notify notify we accept state and some sort of like data right here well we accept data right here but i want to destructure that and take out message from here and type okay first i'm going to set the show property to true i'm going to assign the type and message as well and i want to hide the notification up to three seconds so i'm going to write set timeout after three seconds just hide the notification now we need to go in the survey view and whenever the survey was successfully updated right here i'm going to call store commit notify okay and i'm going to pass type to be success and message message should be survey was successfully updated let's save this and have a look let's scroll down below hit save and we got this notification so it will successfully update it which disappears after three seconds the last thing we need to do here is to add some nice animation for this i'm going to go in the talent config and create extend the theme and create animation right here i'm going to define keyframes right here and the name will be fading down i'm going to find from and to inside the from the transform needs to be translate y so the basically the object will go a little bit up from position will be minus 0.75 ram and the opposite will be 0 and 2 position will be transform translate 0 and the opposite will be 1. and down below these keyframes we're going to add animation and fading down corresponds to fading down 0.2 seconds easing out and both if we save this and have a look let's hit say right here and we see this nice animation this looks awesome look at this now i want to apply this nice animation to the list of the surveys so whenever we have at least i want this list to nicely fade on one after another so let's go in the survey i'm going to close everything and open surveys and at the top we iterate over survey list items and right here i'm going to add class with opacity opposite in sub-zero the i'm going to use the animate animate fading down and let's have a look so far how this looks like if i just reload the page we have this nice animation but all of them animate it once i want one by another like one after another like in the style i'm going to define the animation animation delay needs to be based on the index of the current iteration so i'm going to use index right here and animation delay needs to be that index multiplied on 0.1 second something like this okay if i save this and have a look reload the page and we see this nice animation look at this they animate one after another that looks awesome if i just click edit i want to add animation right here as well so i'm going to open uh survey view and let's find the place where we have worm and on the form i'm going to add class ani oops animate fading down save this and reload the page we have this nice animation here as well when we reload the service we see an empty screen until the service actually is fetched so we don't use this loading property on the viewix so i'm going to define right here if survey is in loading state we show loading text otherwise in vls we're going to show the actual surveys so let's have a look reload the page we don't see anything why because i think i know the reason down below with the survey is equals to the surveys data but i want to change this and the surveys equals to state surveys but we're going to iterate over surveys data and we're going to show surveys loading right here save this and have a look reload the page we see loading and then the list appears now i'm going to implement pagination as well right here okay down below actually i'm gonna wrap the pagination and this one in a new div right here in the v else let's wrap it okay and down below i'm gonna define pagination okay let's observe how we're gonna do the pagination whenever we get surveys we have the following information links and meta links contain like first and last links but they don't seem to be working of course we can have like have a look in the laravel documentation and make them working but i don't need that links i need meta because the meter contains everything like how many items we have one per page are two what is two what is total what's the current path and the links that links actually contains everything what we are interested like if we go in the backend side and open the controller survey controller and scroll at the top to find the index right here we have the pagination 50. i'm going to set it to 5. now let's have a look reload the page click on this and go in the meta links you see we have six links the first one is the previous the next one is the label one and the url as well so urls seems to be correct as well okay so what if we just iterate over those links and just display the buttons and whenever the button is clicked we're going to make requests on the following url to actually fetch the data okay i think we can do this let's go in the viewix and define links on the surveys let's scroll up we have surveys right here we have loading we have data i'm going to define links to be an array and in the surveys we can use that links by accessing surveys dot links and let's just print that information surveys dot links and whenever we get the response in the viewix as well and that should be done in the mutation set surveys we have the surveys and let's duplicate this and we're going to take links from mita links and assign it to surveys links now if we have a look in the browser and down below we have all those links look at this so we just need to iterate and just render them properly let's go in the surveys delete this and render them right here okay i'm going to create one wrapper div element with a flex then justify center and some margin top then i'm going to create now item with some tile on css classes like inlineplex justify center round it and so on down below i'm going to create i'm going to start already iterating my surveys links and i'm going to just take out the link in the index i'm going to use the index to be key and i'm going to disable this link if the link url doesn't exist and that's going to happen whenever we the previous for example doesn't have any url because we are on the first page in this case it's going to be disabled and i'm going to use this vhtml so let's have a look so far down below we already have content rendered but we need to apply proper styling on this oops on this um where it is a element okay so we're going to add like click event handler area current and classes those classes are general classes like display inline flex item center some padding border text small white space no rub and so on okay save this and have a look this looks nicer so far but we're gonna add classes again and right here i'm gonna use conditional statement to add classes like for example if link is active we're going to add the index as well as background indigo border indigo and text indigo otherwise we're going to add background white and border gray and text gray save this and have a look now this looks already good i'm going to add one more thing if the index current index of the link is 0 this means that this is the first button i'm going to add rounded left md and save this and have a look now we see that the left side of the pagination is rounded and i'm going to add one additional statement if the index is survey links length minus one if this is the last link i'm going to round it right md let's save this and have a look now we have this nice pagination now we need to create that get for page let's scroll down below let's create right here a function get for page which accepts link we're going to do an if statement if the link url doesn't exist or link is already active we just don't do anything and return immediately otherwise we're going to call dispatch get surveys and we're going to pass the link url as a url inside that object payload object now if we go in the get surveys get surveys action right here we're going to accept right here payload object and take out url from there okay but sometimes we call the get surveys without any additional argument for example at the top we call it without additional arguments so we need to assume that the this object basically has a default value of an empty object okay and if the url is not presented there we can give it also a default value of now now we need to do um we need to check if the url basically is now we're going to take uh slash survey whatever is written right here okay and we're gonna pass url so we accept url if the url exists we take that otherwise we make requests on slash survey now let's save this and have a look in the browser so let's zoom out slightly we are displaying i think five items here we have that now if i click on two now we get next five items the request was made with the page number two now this is the third page this is fourth page and that's it we have successfully implemented pagination the previous and the next button will also work and the index is currently active as well so if we just reach to the end then click on next nothing really happens however the scroll jumps at the top this happens because in the surveys right here we need to pass an event and we just need to call even prevent default because this has href right here okay so let's scroll down below we get event and on event we're gonna call prevent default save this and have a look next next next and nothing really happens or if we click on the same button nothing really happens okay congratulations you have successfully implemented pagination now i want to start working on a public page survey creation doesn't mean anything if you are not able to take the survey and complete that okay right here next to this delete button on the left side i'm going to add a link which is going to open the survey uh in a new tab it's going to be the how how you basically should take the survey and finish that and anyone can use that url send to friends or share on social media to ask them to complete the survey okay let's go in the vs code and open that survey list item and right here we have this edit button rotor link we have this delete button on the right side i want to basically create a div right here give it a class of flex and items center and right here i'm going to put this delete button and before the delete button let's collapse the button i want to put right here that link okay first let's create a element then i'm going to add ahref right there the href will review survey and the survey slack i'm going to also add the target blank right here let's add couple of talon css classes to this link and finally right here we're gonna put an svg icon copied from the hero icons let's have a look in the browser so we see this nice link whenever we click that new tab opens right now the url is not configured but we have the button okay now let's create the new view i'm going to go in the views section right here and i'm going to create a file called survey public view dot view file let's generate boilerplate code right here and we're going to get back to this we can just write public view save that and we need to open now rotor and configure a new road right here okay down below the dashboard i'm going to write new url road the path will be slash view slash survey slash and right here we're gonna get a variable called slug and then we need to specify the name as well that's gonna be survey public view and the component will be survey public view okay let's import that survey public view so i'm going to just duplicate the register and change this into survey public view let's save this and go in the browser click on this button and we see this public view okay our road is ready our component is ready let's go in the survey public view and work right here let's remove this export default and i'm going to add setup on the script tag let's collapse the styles and here we start all right let's start everything with a div with some padding inside there i'm going to check if the loading flag is true we're going to show some loading indicator just like we did in a survey view or in a survey list page we need to show some loading indicator until the survey loads in the vls we're going to render the form with container and margin horizontal auto to be the to the container in the center basically okay we also add a submit event handler with the submit survey the functions which i'm putting right here doesn't exist yet but we're going to create of course down below we create a d with the grid display and we show it six columns on the left side we're gonna show an image on the right side we're going to show title and description we put right here in image we put the title in the h1 tag with text 3x large and margin button we also put a description inside the paragraph with text gray and text small all right down below we need to create another div which is going to be the wrapper for every survey questions we're going to start iterating over our survey questions and we're going to create a new component called question viewer and on that question viewer we're going to pass v-modal and that's going to be answers objects inside this component which we'll describe right now we're going to pass also the question in the index okay down below we're going to create a submit button with a lot of talent css classes those classes are repeated in many places in the application but in the future we're going to optimize this and create reusable components we're going to also create component for this button okay now above this div i'm going to create another d which is going to be check if survey is already finished we're going to handle this case as well if the server is already finished we're going to show some display some green notification that you have successfully finished the survey something like this otherwise we display the questions right so we're going to add classes to that survey finish d with background emerald text white some fixed width and inside there we're going to put the text thank you for participating in this survey all right and we're going to also show a button right here submit another response whenever user clicks on that the page resets and user will be able to submit another survey again those classes are repeated in many places the pattern classes but we're going to take here this a little bit later all right let's move down below and create functions and variables in the script let's first create a question viewer component i'm going to go in the component section and create right here a folder called viewer inside there i'm going to create question viewer dot view file let's generate the boilerplate and view question save that and go in the survey public view first we're going to import question viewer from the components viewer question viewer then we're going to import computed and ref also because we're going to need them i'm going to import the use a road from the view router and create route i'm gonna import user store from the viewix and create store as well okay down below i'm going to create already a loading indicator which is going to be computed property from store state current survey loading that's the same state we are using in the survey view okay we're going to also get this survey from store state current survey dot data that's going to be also computed property all right down below i'm going to create a constant variable survey finished which is going to be the default value false and that's going to be the indicator when the survey is finished or not i'm going to also create a variable for answers which has default value and object the answers will help the following pattern it's going to have the following format it's going to be an object and the key will be the question id and the value will be the chosen answer or answers on that question all right down below we're going to make a request to get this survey by its slack because we implement it in the url to have the service log that's good for seo so for search engines and now we need to make requests to get that by slug that get survey by slug doesn't exist in this store we're going to create it down below we can already create submit survey function let's first print what's going to be the answers.value i'm going to stringify that and show as a json in the console with the indentation of two just to have a nice output okay next we're going to make requests to save the answers we're going to call this action save survey answer and we're going to pass an object right here we're going to pass the survey id which is going to be survey.value.id and we're going to pass also the answers which is going to be answers.value okay whenever we got the response we need to check if the response status is 201 it means that the server successfully saved the answer on the backend and we can just show the survey finished success notification okay and down below we need to create submit another response function inside which we simply reset answers value we called an empty object and the survey finished equals false which means that the form will be basically reset okay so far so good we can go on the front-end side reload the page and in the console we should see an error get survey by slack so let's go let's open store and create get survey by slug right here we create the function we accept the comments as the first parameter with the structure the first parameter object and take out comment from there we get the slug as well now we need to indicate that the loading has been started so i set current survey loading to be true then we're going to make an http request on survey by slug endpoint and we're going to pass the slug as an argument that endpoint doesn't exist yet but we're going to create that inside then of that request we set the current survey to be res.data and we also disable the survey loading and we return the response we listen also catch inside catch we disable survey loading and throw an error all right we have this action already ready let's remove this line now if we go in the browser and reload we see the http not found error basically okay we need to go on the back inside and create that endpoint all right let's open api dot php first and right here we have a couple of actions and basically we need to add this endpoint to be out of road middleware sanctum so unauthorized guest users should also be able to make requests on the following endpoint so right here probably before the register we're going to create that route we need to define get endpoint and the url will be survey by slug slash survey and we need to indicate right here survey controllers and we can use uh show mix show method show action of the survey controller let's open survey controller and open the show but right here we have check if the survey user id doesn't equal to the current user id which will not be relevant if we are trying to access that as a guest okay that's not going to be relevant so we have to probably create another action and okay we could call this survey for guest for example we're going to duplicate this and create down below survey for guest and let's remove this request parameter and we need to remove that if statement as well okay everything else will be the same it's very simple we just return the survey let's go in the api and right here we need to specify an action show for guest show for guest yeah we have the correct naming and at the top we need to import the survey controller as well and we can actually replace this one with the use as well okay we have an endpoint however because we have indicated that the parameter name survey right here and we are using right here in survey model laravel will basically guess that whatever comes right here is a primary key of the survey model and try to resolve and select a survey for me however this will not work in this case because we are passing right here id okay sorry we're passing right here slug if we would pass an id instead of slug in the http request that would work okay however there's a method in the api configuration right here to specify that whenever we get the survey right here i want to select the survey by slog okay colon and slack in such case whenever laravel tries to select the survey it's going to survey it's going to select the survey by slack let's save this and reload the page and right here we see already successfully returned response with data and everything the questions also okay perfect so we have title we have description and we have view question four times and that basically comes from the this one question viewer looks awesome let's actually collapse the developer tools and now we need to work on the view question viewer component let's remove this export default and add setup right here let's define props right here we're going to define question to be an object index to be number and we need to define modal value as well which can be string or array so those are the props which are passed from survey public view if we scroll up from here we pass those things and whenever we pass the model from here that's going to be accepted as a modal value inside the props okay then we're gonna destructure that props and take out question index and modal value and just like that we can already use them in the template down below we're going to define emits and that's going to be update model value if we want to set up two-way binding using v-model we need to emit an event called update column model value okay then we're going to import ref from here and i'm going to define a model and if question type is check box the model equals to ref and empty object the model basically will only only be used for the checkbox types and that's necessary because checkbox has can have multiple answers and we're going to say that in an object where option option uuid checkbox option uid corresponds either true or false that that option is marked or not okay that's it so far we have our script so far ready and we can move on the template all right let's define field set right here with slide margin bottom inside there i'm going to create two divs one will be for the question title and description second will be for options of this question and down below i'm going to create horizontal line okay inside the first two we're going to put a legend which is going to be the question description question text with the index of that question as well and let's actually save this and we should be able to see a result so far so let's reload the page and just like this we see questions okay let's move on and down below we're going to create a question description as a paragraph and inside the second d we're going to write several if else statements and that we need to handle each individual question type differently okay if it's a select we need to show select of course with talon css classes and we need to show we need to give that select a value which is going to be the model value and we need to also listen to change event and whenever this happens we need to emit update model value with the event target value okay inside the select we need to start iterating over question data options um we need to display them however we need to also display select all so please select uh option inside the select okay and let's also add value to each individual option to be option.txt and key as well let's save this and have a look now we see please select and we can select any of those options okay now let's continue and move down on a question type radio we start iterating over options of question data options we add right here class like flex and item center we need this because we're going to display input as well as the label and we need them aligned to be properly we show input right here with an id which is going to be the option uh uuid and we add name as well to radio every radio in a single question needs to have the same name okay otherwise you would be able to select multiple radios so we add also a value to be option dot text and we add change event as well that's gonna emit update model value with the event target value okay down below the input we're gonna show label which has a four for option uid some classes and option text let's save this and we can have a look so far reload the page we probably don't have radio questions in this survey that's why we don't see them okay let's move on now for the checkbox we do something similar we did for the radio we start iterating over our options we give it a class we show input type checkbox we give it a v model in this case we give it a v model and that's going to be the model option text okay the model as i mentioned is an object right here however i mentioned that the um this object key was uid but actually it's a text and the chain on on change will listen to that and we need to emit that event okay we need to create that own checkbox change function later down below we create label now if you save this and have a look now we see checkbox questions how they look like okay let's continue and down below for input type text that's pretty straightforward we show input type text with the value to be modal value and we emit an event on input for text area we do the same we give the value to be model value and we emit an event on input okay now we save this and we have all questions basically so if we just go in the survey and open this one which has most of the questions actually i don't want to edit i want to open in a new tab now we see all those questions we see checkboxes and these are radios and now you see that the this one works fine however if we sorry if we basically go in the input type radio here and remove this name we see that we will be able to select multiple multiple radio options okay so we save that and that's how it should be and yeah just like these we have most of the things ready now let's go down below in the script area and we need to create on checkboxchange function okay before we do this let's actually observe how the checkbox values look like so i'm going to create a pre-tag right here and display model let's save this and have a look look at this click on laravel we see laravel equals true click on e2 e2 equals two if i antique laravel that's gonna turn into false so the text is either presented in the object and is true or it's basically not presented which means it's also false okay so now let's remove this and down below let's define this function okay we define a function on checkbox change we create a constant variable selected options i want to finally emit an array of texts okay let's continue and i'm gonna start iterating over modal value where this one will be basically not the uid but that's gonna be a key of the modal value in our example that's gonna be the text then i'm gonna check if the inside the modal value there exists for the giving uid something that's going to be text as i mentioned and finally we're going to put that in the selected options okay that one and again down below we're going to emit an update modal value invent with selected options let me actually change this to be text okay that's gonna be more clear and just like this the selected options will contain all the selected texts like laravel e2 card igniter as an array okay let's save this and go go in the survey public view and we have right here answers and let's print answers in the console basically so we actually print that answers in the console right here so let's bring up the terminal go in the console and let's fill up the form okay so i'm going to select georgia select those two select laravel eight all of the above something right here and favorite channel that's going to be traversing d okay i'm going to click on submit and let's go in the info section so right here we see that the question number 15 has an answer georgia16 has javascript and php 17 has laravel e2 and so on you get the idea so that's exactly how we want it and finally we have this whole json which needs to be sent on the back inside we don't have that save survey answer action yet created in the store so we need to go now in the store and create that okay down below git survey by slug let's create the function here we create a save survey answer we get the context object in the structure take out comment we have the payload and take out survey id and answers from here we make an http request and pass the answers and inside the url we specify the survey id so our url basically looks like survey slash server id slash answer and we need to define that endpoint on the backend side and we immediately return whatever comes from here so we don't handle we don't update state whenever this happens let's put comma right here and now let's go in the browser and try to make requests i don't need to fill everything in order to be able to make requests go in the network click on submit and the request was made in the url we have survey id in the payload we pass all the answers those are only selected answers we have because we haven't selected everything we don't see everything right here but of course we got not found because that endpoint doesn't exist yet so let's go on the back end and create that okay down below this gate survey by slug let's create a post method of post roads basically survey survey variable right here in the answer and we pass right here store survey action the star survey doesn't exist and we need to create this right now let's open survey controller and down below probably below the show for guests let's create it right here let's define right here store answer we accept a survey model right here but we want to also accept right here store request object that's going to be something like store survey answer request just like we have um for store or update of the where is that here it is just like we have update survey request or store survey requests we need survey answer request so i'm going to bring up the terminal and run php artisan make colon and request and i'm going to call this store survey answer request hit enter and the request was generated let's go in the app http requests we have that store survey request first of all let's change these authorized into true and down below inside the rules we're gonna specify that the request contains answers basically and that's the only thing it contains that's gonna be required for sure and it's gonna be airy okay and that indicates that in the request in the payload we pass answers that's going to be array actually for javascript it's an object but for php that's going to be associative array where key corresponds to some value all right we have that store survey request now let's go in the survey controller and we need to use that store survey request right here and let's scroll up and write a use statement to use that store survey answer request all right now down below let's continue and we need to take out the validated data from that request then we can already call survey answer do you remember our table structure let's go in the database migrations and right here we have surveys survey questions survey answers and several question answers okay so we need to first save a record in the survey on source table and then we need to save answers in survey question answers okay so let's continue and in the survey answer we pass survey id we pass start date and end date in this case both will be the same and down below we start iterating over our validated answers it's going to be an associative array where key is the question id and the value is an answer but we need to also check if the question is actually valid in terms of if the question id comes on the same survey on which the user is doing so that kind of security checks are very important on production ready applications like technically someone uh can send right here question id like hundred which doesn't belong to this survey but belongs to another survey and if we don't do any validation check we simply save in the database that question uh like hundred has that following answer which is not correct so we're gonna make a query in the database from the survey question passing the id of the question as well as the survey id if we just only pass id and delete that survey id that's not going to be enough okay we need to pass that this question definitely belongs to following survey and if the question doesn't exist we return invalid question id with 400 status code otherwise we continue and we create data to be saved in the survey question answers table so we pass in the data survey question id and survey answer id and we also pass the answer if the answer is an array and this is the case if it's an area we need to json encode that and save it in the database like that okay and finally we need to call survey question answer create and down below we need to return um basically we can return an empty response but the status code needs to be 201 because we are listening to that status code on the front-end side and now let's scroll up and we need to write use statements to use survey answer and survey question answer all right let's now hit the submit button and have a look we got the status code 500 so we have an error a survey id to fillable property to allow mass assignment on survey answer that's correct we need to open survey survey answer and right here we need to add a fillable and specify survey id right here let's actually see what properties we are assigning to survey answer this is the survey answer we have start a date and end date as well so let's put start date and end date right here let's actually open the migrations for survey answers table and have a look we have survey id started and ended so we don't have anything else so so far this list looks good but we need to add that fillable to survey question answer because we are assigning some values there as well so let's define fillable here and let's have a look in the survey question answer migration and we have survey question id let's put this right here we have survey answer id and we have answer as well and we have timestamps but we don't want them to put in this available so let's save this and hit the submit button again and we have 500 again column not found unloan unknown column updated it that's valid because our survey answer model does not have the dates again have a look at immigration survey answers table this one doesn't have time stamps for created it and updated it so we need to open let's close this we need to open the model and right here we need to define uh created column to be null should be now and updated at column to be null as well now let's save this and hit submit again and something is going on so we got status code 201 created and we immediately saw that uh thank you for participating in this survey message which indicates that the response was saved in the database so now let's go in the localhost slash phpmy admin and check if the record was actually saved in the database so let's go in the laravel survey okay for some reason my php my admin is broken i'm not going to spend time on that um i generally use that for um for tutorials you can check on your phpmyadmin it won't be broken on your side probably and i use phpstorm's built-in database tool so let's click on survey answers and right here we see a lot of so basically i i was testing of course uh and i have much more answers but what we are interested in if new answer is added right here right so if we go in the browser and submit another one let's choose a couple of options don't need to fill up everything let's open survey question answers as well we have like 39 39 records here i'm gonna click on submit we get the success response let's reload these here two responses to answers we are edited in the survey question answers table georgia javascript php and in the survey answers one additional record was made so this proves that the process of saving of answers works perfectly which is awesome next i want to work on the dashboard let's open phpstorm and i'm going to generate dashboard controller let's bring up the terminal and i'm going to run php artisan make controller dashboard controller let's hit enter the dashboard controller was generated let's go in the up http controllers and open dashboard controller i'm going to create right here an action index and return a couple of information from here i will need to access request probably as well and i will probably need to take user from the request and now i'm going to select couple of information i want to select total number number of surveys user has i want to select latest survey and display that on the dashboard i want to get total number of answers and i want to select latest five answers and show that to the dashboard all right let's start implementation step by step i want to first select total number of surveys for this i'm going to make query on the survey i'm going to add where clause where the user id of the survey equals the current authorized user id and i'm going to call count on that the first one is very easy next i want to select latest survey again i start select from the survey then i add a where clause right here i want to sort the surveys by creating edge descending and that's what this latest method does and then i want to grab the very first survey after we started that okay we have the latest survey let's move on i want to select total number of surveys and the select starts from survey answer then we joined it to the surveys table with the survey answer survey id okay next we had a where clause that the survey user id equals the currently authorized user id that we are closed the user id check is always necessary because we are displaying the dashboard for a specific user right next i call count and right here i have total answers count and finally the most challenging one is the latest five answers okay again we start the query from the survey answers we join to the surveys again next we add a where clause which is the identical what we have above next we sort this by the end date descending we could also write latest end date right here next we limit to select only five but finally we need to select the latest answer so i call get models and we select everything from survey answers table all right we have all this data i'm going to return an associative array with total answers with the latest survey with total answers sorry for total surveys latest survey total answers and finally i'm gonna return latest answers but i want to also create a resource for that okay for the latest answers let's see let's actually bring up the terminal and generate resource php artisan make resource we're going to call that survey answer resource hit enter on that let's actually collapse the terminal and open survey answer resource okay and we need to adjust this to array method we need to return id from here this id we need to return survey information as well and this is going to be i'm going to use survey resource right here so it's going to be new survey resource and we're going to pass this survey and we probably need to update the survey outsource model to add a relationship to the survey let's finish this one first and we're going to also return end date when the survey was actually finished so that's going to be this and date all right now let's open survey dot php survey model which this one has many to questions we need to duplicate this and add his menu on answers as well it's going to be survey on store and if we open survey answer we need to add right here belongs to this one belongs to return this actually this should be sorry it should be survey and this belongs to survey column colon plus all right just like this from the survey answer resource this survey will work all right let's go in the dashboard controller and right here i'm going to use latest answers to be survey answer resource collection now let's move above and import the classes like survey survey answer survey resource as well as survey answer resource okay we imported them now let's open um api.php and we need to add right here as a protected route dashboard dashboard index so we're going to call road get dashboard slash index will be dashboard controller class index method we can replace this with the import and the dashboard controller will be imported right here all right we have the back end almost ready i think we have it ready now we need to move on the front end and make requests let me actually remove this index from here not necessary now let's open vs code go in the views and edit the dashboard file so this is the place we need to make some changes let's actually open the store first because i want to define a dashboard state right there let's move up and right here i'm going to define dashboard to be an object dashboard with the loading indicator to be false by default and data which is going to be object okay now let's move on on the dashboard view and right here we need to make requests to get the dashboard data then watch the data get the data and display it okay first we're going to import user store from ux and create store next i'm going to import computed from view and i'm going to create two constant variables for loading and data it's going to be computed properties from store state next i'm going to make a call of dispatch method on the store with the action get dashboard data that get dashboard data doesn't exist yet and we have to create this let's open the store scroll down below go in the action section and right here i'm going to create git dashboard data we create function get dashboard data we need to start the loading indicator so i'm going to call a mutation dashboard loading with the flag tool then i'm going to make an http request on slash dashboard endpoint and then we disable the loading stop the loading and set the dashboard data to be res.data and we return the result and in the catch we disable the loading and return the error now let's move down below and we need to create these two mutations dashboard loading and set dashboard data those are pretty straightforward mutations we accept loading and set it in the dashboard state we accept the data and set it in the dashboard data all right we have everything ready and let's go in the dashboard and right here we're going to print um i'm going to put in the pre-tags loading and data let's save this and have a look in the browser here we have loading false and we have the data if we just reload we have loading true and then we get the data so the request was works perfectly and now we need to work on displaying that data on the dashboard let's delete the pre-text and create marker first i'm going to check if the loading indicator is true we're going to display loading text in the vls we're going to create div with the class grid i'm going to use grid layout to display my items okay on that div element i'm going to add grid calls 1. so on a mobile screen i want all those four cards i want to create four cards as we are returning four different types of information from the back end so i went on a mobile layout to show only one card in a width on a medium screens i want to show two cards and on large screens i want to show three cards okay however i'm going to use a row spawn as well and you're going to see all this okay next i'm going to add gap between the cards and i want to make everything text gray 700 okay inside the div i want to add as i mentioned four different cards each card will have background white shadow md padding some of them might have text center flex or something like this you're going to see but [Music] each all of those cards basically will have order property i want those cards to rearrange on a mobile screen so on a mobile screen this one will have order one but on a larger screen it's gonna change its order position okay let's actually create all four cards okay with the background and shadow and all the necessary things and with their default orders okay order one order two order three and this one has order four now let's add uh order position for larger screens like this one we'll have an order two on a larger screen this one has will have order four on a larger screen this one have order one and this one have order three okay let's save this and have a look in the browser so far okay this is how it looks so on the left side right here in this card we're going to show latest latest survey information like the title and image and a number of views um a number of um we don't track number of views but number of answers and the uh edit and the probably view answers button as well right here i want to show total number of surveys i have and total number of answers and on the right side i want to show the latest five answers all right let's go in the vs code and now i want to add animation class to all those four divs to have some nice animation okay if i save this and reload the page i see all of them animate but i want them to be animated one by another so i want to add animation delay on the first one first d which actually is the or which has order two on a large screen i want this one to have uh animation delay 0.2 second on a which has order 4 this one will have animation delete 0.3 second and this one doesn't have any kind of animation okay if i say this and reload i see this animating they are animating nicely on desktop screen we need to handle this on a mobile but uh let's actually focus on the content okay um like on a mobile screen when they change the ordering the animation delay should be also changed uh okay but let's as i mentioned focus on the content oops what i did um okay now let's focus on the content right here we're gonna put h3 tag with the total surveys and this that's actually order uh to the second div okay on uh on desktop we're gonna add uh right here d with the data total surveys and this is what we have let's add a little bit of classes like this one i want to make the text to be very large from semi-bold and things like that let's save this and now this is nice let's move on and on the um i want to actually yeah let's create another one total answers right here we had also total answers with some classes and this is total answers down below we need to create a latest survey and we're going to display an image data later survey image url we're going to display title and we're going to display upload date as well and we're going to display answers total answers this one has okay let's down below and we're going to add two buttons one for edit survey another for delete for the edit we're going to add two as well to the survey view page with the data listed survey id let's add talon css classes right here and let's add a pencil icon hero icon as well okay save this and have a look okay this is how it looks down below we're gonna add delete button we view surveys with classes and with hero like let's save this and this is how it looks now let's move on on the last div right here we're gonna create a wrapper that's gonna be basically for the header inside the header we're gonna have latest survey title and view all button the view all button will not be implemented at the moment we're going to implement this later down below i'm going to start iterating over latest surveys as in a tag and we're gonna add classes to this one as well and output a survey answer survey title on which survey the answer was made and the date when the answer was made okay we save this and this is the information okay what we have so far okay this looks awesome and i think the dashboard has all the kind of information we want and we don't need to do anything right here so we don't implement the view answers uh yet and view all which basically do uh something similar that's gonna give us possibility to see all answers that's gonna give us possibility to see answers of that survey and that should be uh specific answers like this specific one okay if we just go to surveys and go back to dashboard they are animating nicely and we have that let's check how they look on smaller screens that's the medium screen size and that's the mobile and this is exactly what i wanted one thing to note right here these answers does not reflect the answers on that latest survey that's incorrect information in this bug of the code so this one displays the total answers which we need to fix and i also want to fix the following thing upload date which looks ugly to me and i want to change the format of that let's actually go on the back end and i want to open survey answer resource and let's change the date first of all to be new date time we're gonna pass the end date and finally format that into your month day hour minute and second let's we need to put this new date time in a parenthesis just like this save and reload we don't get that okay let's go on the front side and have a look what information we get so we get the yeah we get the survey upload date like that's the survey create date actually and that's actually correct latest survey created it so we don't need to do probably anything right here that's going to affect the following place instead we need to go on the survey resource and right here we need to change the created date and updated it to be new date time new date time and format them just like we did your month day hour minute and second okay and we need to wrap this in a parenthesis all right let's now have a look okay the date looks much better now let's take care of the answers so if we go on the view js side we have the latest survey created but the data total answers which is incorrect so right here we need to return our latest survey answers okay but the latest survey doesn't have answers that is the latest survey okay and this one does not have answers if we could of course implement answers right here but that's not actually a good idea because every time we open the listing of the service if we go in the service listing we are getting right here questions and now we're gonna get answers as well even getting the questions is not good idea if we just have a look in the network and reload the page right here in the response let's have a look in the data each individual survey has questions array that's questions can be very large data and we are just loading unnecessary information at that stage so it's very common to create a different resource for collection and different resource when you're actually fetching the data or that specific item so in this case we need to come up to two different resources okay the easiest solution in my opinion will be to create a different resource for the dashboard so let's open the project site and right here let's go in the http resources and i'm going to copy and paste survey resource and i'm going to call this survey survey resource dashboard oops dashboard all right let's add this i'm going to change the name survey resource dashboard looks good and let's change these two array so we need image url we need title we need slug let's return status but we don't need description so description is something we never need on that uh on that area so we can remove this description from that resource we need to create that to show right here but we don't need updated it so we can remove this we don't display expired date but we can display this right here as well as the status so that will be nice to display right here on that later survey card so we're going to do that we don't need questions however we can also display that information but we for sure we don't need the collection for the questions the only thing we might we might need is the how many questions that survey has so let's actually remove the survey question collection from here and we can uh chain method the questions returns a query object and we could call count on that okay let's save this and we need to do something similar for answers let's put comma right here oops answers let's save this now let's go in the dashboard controller and we need to change the this place we don't need to return server resource we need to return survey resource dashboard let's move up and remove survey resource let's save this and have a look reload the page okay now let's inspect this and see what kind of information we get reload again we get the latest survey this one has answers to be won expire date created at image url questions also one slug and everything as we expect if we just edit that survey and have a look it has only one question let's add another question that's going to be question 0 for example let's save this it was updated if we go in the dashboard and inspect that and reload we see on the latest survey questions to be to okay so that is exactly what we want now let's go on the front hand side and right here we need to display latest survey dot answers that's going to be number of answers and here we have one we can duplicate this and let's make the first one to be questions it's going to be number of questions save this and we see questions and answers this one has margin bottom three so let's just make it into one that looks better and we could display status as well as the expired date so i'm going to duplicate this two times and let's call this expire date to be expire date save this and have a look and the last one can be status and that's going to be if the latest survey status is active we're going to write if that's true we're going to write active otherwise we're going to write draft right here so now we have all the information about the survey like create date expire date a status number of questions and answers and that information is accurate now i want to make a couple of improvements in the project the first one is that on a mobile screen this default image is broken so let's open vs code now we need to open default layout and find the place where we just don't use that default icon that's going to be down below so right here we still use the user image url which actually doesn't exist so we need to use default icon right here so this line 153. let's move up and find the place where we are already using hero icon for the user and i guess this is the yeah this is the icon so i'm going to copy that svg move down below line 153 right here and i'm going to replace this with this svg icon so let's format the code save this and open and now we see this nice user icon we can actually increase the width of that a little bit yeah that's much better let's remove the developer tools and we need to increase the width on the um desktop as well so let's move up and change this into 8 8 and with both okay that's much better next what i want to do is whenever we log out and when we click the sign in button if the sign in needs like signing needs half a second maybe a second so we need to show a loading uh indicator right here when we're trying to when we hit design button basically okay so hit on that loading and then we we will be logged in inside the system okay i'm going to now open halwing css.com go in the docs and find right here spinner i want to take the css spinner the animation that's the that's the thing i want to get so this one doesn't give me a code right here for that actual um svg so i'm going to inspect that this is the svg so i'm going to copy that and now go in the login page so let's actually close the default layout and open login.view move down below find that sign in button and right here let's put this i'm going to paste this so let's save everything and have a look now i see this nice spinner however i want this to be displayed only when the user clicks and there is loading indicator okay so right here probably before the error message i'm going to define let's can be constant as well const loading equals ref false so by default loading is false whenever user clicks on loading button we set the loading value equals loading dot value equals true and whenever we got the callback and then we set this into false as well as if we got an error so i'm going to copy and paste this right here as well so at the top we need to only display the svg if the loading indicator is true and we need to also disable the button if the loading indicator is true so disabled equals loading now let's save this and have a look so if i click the button loading appears and the python is actually disabled let's sign out let's try once again click on this we get the loading and the button is disabled okay if we just go in the network and change this into let's actually assign note and change this into like fast 3g we click on that the button is actually disabled i think we need to change this into slow 3g click on that now the button is disabled even if you continue clicking on that nothing really happens but the it would be nice if this tile changes um so that it's it's more it looks more like a disabled okay let's change this into let's actually leave this into slow 3g open the login view and right here on this button i want to add class and i want to add two properties first is uh cursor not allowed and we need to show that if the loading indicator is true and second is on a hover we need to show pg indigo 500 okay now and that's actually to be displayed if the loading again is true now let's save this and click on this and we see cursor basically disabled let's change this into no throttling sign out click on that that looks much better another thing we need to improve is the signup page so if we go on sign a page and fill up the email for example which is already used we're going to get error error from the back end but the errors are not handled properly on the front-end side and user doesn't see those errors which is not very good and user friendly so let's take care of this i'm going to open register view and let's make some changes here okay right here i'm going to define a constant errors variable which equals to ref and the ref was automatically imported from view reactivity if you are manually importing you can import from here or just from view and we're going to pass an empty object right here because that's going to be finally an object and we need to add catch case right here inside the catch we get error and that error basically contains a response and the response contains the status code so we need to check if that error response status equals 422 which indicates that this is a validation error the errors dot value equals error response data and that data basically is everything received from the backend so that's the whole whole response but we are interested inside the errors we need to display that so data dot errors just like this and now if we move up and we need to display that errors somewhere right here maybe so let's just put inside the pre-tags those errors save this now if we fill up the form now we get that error the email has already been taken password confirmation doesn't match and we have we have a bunch of errors so we need to display them on the login page we are using um some component talent classes like where is it this one which is inside the form which has background red and so on which is for displaying errors so we can take this and copy and paste into register however i want to make a reusable component now so that whenever uh we need that we don't copy and paste okay so i'm gonna grab this and in the component section i'm going to create a component called alert dot view okay let's generate the boilerplate code and paste this right here now what do we need we need error message actually i'm going to do it in the simplest way okay so i want to just remove this wave i want to remove that span uh let's remove the whole span and i want to change this and put right here slot okay that's going to be slot so everything else i'm going to leave it as it is so i don't touch in the login however i'm going to change these to use alert component and that error message will go inside there and if we want that close button to be displayed as well so we will put this right here as well okay so that's the simplest solution however the classes are basically repeated so we created this component for classes and let's add right here that the same the if and let's remove this div let's first test if that actually works on a login page so if we just enter incorrect password we get that the provided credentials are incorrect which means that this works pay attention that the alert was automatically imported by vs code when we started typing so down below you need to import that alert okay and if i click that basically disappears if we go in the register now uh we need to use the same alert so probably inside the form right here i'm going to create alert that remember basically is not relevant for the logging probably we just forgot to remove that so i'm going to remove this so in the alert we put all kind of error messages so we have those errors we need to start iterating over those errors and just display them let's first edit the if so if the object is of the error's length exists which means that if errors is not an empty object we need to display that alert okay if we just save this so far go on the register page fill up that information and hit the submit we should already see an empty error alert which we don't see probably we have some kind of error now we don't have all right all right let's continue and see if we have bug we're going to fix that okay so now we need to add also classes probably that's the reason we don't see them but let's add classes so i'm going to start iterating over my uh object keys of errors i'm going to get the each field that errors remember is an object where key is a field name okay i'm going to take that field i'm going to add right here a key so i'm going to start now iterating over errors of that each individual field if we have a look in the network once again we see that errors can contain errors for multiple fields so first we start iterating over those and we get the errors for email and errors for password then each individual field might have multiple errors like password for example then we start iterating over those errors right here okay we get the actual error from the errors.irs.field not the dot but the field property and for some reason if that does not exist we're going to get an empty array i'm going to bind the key index right here as well and right here we need to output the error so let's save this and now we already see those errors probably the reason why we don't see that red is that the alert is not imported okay if we move down below and write an import statement import alert rom we need to import from component slash alert save this and now we need to fill up this form once again okay now we get all kind of errors email has already been taken the password confirmation does not match the password and so on you get the id right okay we display the validation errors which is awesome um let's actually add the loading indicator just like we did on login so down below right here i'm going to define another constant for loading poles and whenever we start the we make before we make the request we set loading value equals true and inside then we set loading value equals false and we do this same thing inside catch all right and let's move up and let's where's the button yeah right here we have the button so let's go on the login page and we can copy and paste the whole svg but again we can create a component for that actually i want to create dedicated video for creating reusable components in taiwan so let's actually copy and paste this so far and then we can do that later okay i'm going to format the code we have loading on a button we're going to add that's going to be disabled if loading is true save this and let's fill up everything click on that we see loading let's add those classes like cursor not load and background classes to the following button as well all right click on that and this looks good okay we see the loading and which and the disabled state as well now let's prepare our vue.js application for deploying on production for this we need to use environment variables right now if we open source axios axios js right here we have localhost baseurl localhost 8000 which is obviously wrong if we want to deploy this on production so basically we're going to get database url from dot env file so in the source right here next to the source basically i want to create a couple of files first of all i want to create dot in example file which is going to be commented and pushed okay but we're going to create other en files which won't be committed and pushed so i'm going to open git ignore and right here i'm going to write that we want to basically exclude dot en file don't i don't want it to be commented and pushed as well as dot en dot production okay i don't want them to be included in the git now in the en example i'm going to write byte underscore api base url equals http localhost port 8000 okay so every key and we need to copy and paste in this en file whenever we create that that example is just for example so we need to copy and paste and just call this whatever you want in terms of in which environment you want to deploy this i'm going to call this.en file and right here now we have white api based url so every key should start with provide prefix if you want it to be accessed in your project okay right here for example i can already access import meter in and then whatever is the key so this one in this case so if i grab that and let's change this replace with the back ticks so now i want i can replace that localhost with the following and i need to restart my server to start reading ian files and now if we have a look inspect that and fill up the form and click on login so this actually still works however if i open en file and make some changes right there okay and then click the sign in button actually we need to restart the server as i mentioned so now if i fill up the form and click the sign in button we get an error the request was made on the following url okay and that's exactly what we're going to do on production so we're going to create now in dot production dot production and inside the en.production we're going to provide right here production api url so our api url will be um we will be something like api your surveys dot x y z okay okay we're gonna save that and now we're gonna run npm run build which will use that dot em.production and use that right here in the following place and our javascript css is basically ready to access api your surveys.xyz so when we run npm run build it created right here this folder and the this folder is whatever we need to deploy as soon as you log in on your hostinger age panel you need to manage the hosting for your desired website in this case we want to manage your service.xyz so i'm going to go in the hosting section and right here i'm going to click your service.xyz manage button make sure you also choose your desired website from here now let's move down below and find the file manager section i'm going to click on that meanwhile i'm going to open vs code and i'm going to reveal this in explorer right here and basically i want inside the hpanel i want to go in the public html we chose which has the default php so if we open your service.xyz we see this default page we want to delete that so i'm going to click on this hit delete button and i'm going to now copy and paste everything from the this folder into hostinger click upload that's going to take couple of seconds it's uploading everything and here we go now if we just reload this page we see our login so if we inspect this now go in the network and try to log in this one makes requests on api your service.xyz on login which does not exist yet it's not yet deployed so this one will show uh hostinger's default welcome page okay now we need to deploy back end let's go in the hostinger h panel and go in the hosting section now we need to manage api your surveys.xyz i'm going to click manage right here let's scroll down below and find that file manager section again let's go inside public html and we need to delete this default php now we can do something similar and drag and drop all the files of laravel application but i'm not going to do that that's a bad idea first the file size is much more so if we open our application and open in explorer so those are the files we want to drag and drop so we can grab select everything and right click and have a look in the properties so that is 155 megabytes okay we don't want to do that it's going to take much more time and there are hundreds or like even maybe hundreds of thousands of files inside that and it's going to be very very slow so don't try to do that so instead i'm going to show you better and preferred way how you can do deploy that and we're going to use ssh for this let me actually close everything and open h panel again let's go in the hosting section actually let's go back we are already managing this one and down below in the advanced section we have this ssh access okay the ssh will be we're going to use ssh to access to our server and clone the project through using git okay recommended ssh clients are putty or pinguinette in this case i'm going to use putty okay just click on this it will redirect you to the putty download page and download putty for your operating system and it's an installable file just follow click on next buttons and it's gonna install i already have putty so i'm gonna now open ot and try to connect to the server there are two ways to connect to the server one is using password and second is using public private keys so password sometimes is easier but it's not the most secure way and sometimes you forget the password and then you have a headache how you're gonna connect to your server the preferred way is always to connect to through public private keys and if you don't know what i'm talking about no worries about that we're going to generate public private keys right now and we're going to give the public key to to the server and we're going to save private key on our local system and then when we try to connect to the server server knows that i'm authorized user and allows me inside the system okay now we have putty opened and inside putty we can provide sship right here and port as well okay now if i click open right here it's going to ask me username i can provide username then it asks me password but i don't want it to be to ask my password so i'm going to just call this give it a name your service dot xyz xyz and click on save okay i'm going to close putty i don't need at the moment i just saved that ip import i can actually go inside the data one more additional thing go inside the connection data and inside auto login username just put your username okay now you need to go back into the session and hit on save don't forget to do that now if i just cancel that let's open puti once again the information will be already populated okay here's your service xyz i'm going to click load and if we go in the connection data the username is saved okay perfect now i want to generate public private keys i'm going to now open puttygen that's the tool to generate public and private keys you basically need to click on generate button right here and then move mouse randomly and based on your randomness it's going to generate some unique keys okay and that's the key it generated at the moment we can save public key we can save private keys and you should do that that if you're doing this a very first time and what this will do it's gonna save your public private keys in your home directory under dot ssh folder right here okay i already have generated my public and private keys that's why i'm not going to actually save them but just click save public keys it's going to ask you to give it a name and the you should specify the location as well to be your home directory uh inside the ssh folder create an ssh folder if that does not exist sometimes there are difficulties creating an ssh folder through the explorer so just google how you can do that okay so i'm going to now close this and i'm going to reopen put it again and now i'm going to click on keys in the menu or file sorry and load private key okay let's go in the i'm going to load my existing private key idrsa.ppk so double click on that and it loaded my public key so i'm going to copy that public key and in the in the h panel we need to first enable ssh access so i'm going to enable that switch okay and down below it asks me to add my public key so i'm going to paste this right here and click add okay it tells me that this is invalid public key why is this invalid okay another way how i can see my public key because probably it's this is not generated using put again that's why it identifies this one as invalid but that's totally fine so i'm going to just close that go in the ssh folder right here and open that public key in using any editor i'm going to open it with vs code open that and here's my public key so i'm going to copy this and now paste it right here you can do the same thing open in vs code now my ssh key was stored successfully now let's open putty load our session and click open now it still asks me for the password because putty does not know that i have private keys in my local system okay i'm going to close this once again reopen it load this go inside the sh section under connection go in the out section and right here under private key file for authentication i'm going to browse and i'm going to choose the file from my ssh folder idrsa.ppk i'm going to click open i'm going to go in the session and hit on save that and open now look at this what happened authenticating with public key imported openssh key last failed login is a couple of minutes ago there were eight failed login attempts since the last successful login so i tried it many times i was testing a couple of things so now we are successfully logged in and on that age panel you have also a couple of basic ssh comments like what the following comments does like ls cd and so on so ls will give us the listing of the files and folders ls dash la will give us in a different format so we have a couple of files right here let me actually expand this okay we have a couple of files right here we have public html we have a couple of files which starts with dot and they are not displayed in the hostinger age panel right here okay so what we need to do is now we need to clone our project inside domains so let's go we need to go inside domains and ls-la right here we see all our domains we have we need to navigate inside cd api your surveys.xyz and type ls.la and we see public html okay what we need to do is to put the whole project inside the following folder so i'm going to basically actually delete that public html and i can delete using rm command or i can delete the whole api your service dot xyz so let's go actually back and i'm going to delete rm dash r api your surveys dot xyz okay now api your surveys.xyz was deleted and i don't see it right here now i'm going to clone my project okay now i'm going to open github go in the repositories and get that project i'm going to click copy the following url and i'm going to run it learn and paste the following url okay so whatever you are doing if you're following this tutorial until now you need to push your project somewhere github is the best place you can make it even public if you want okay and you can you need to push and right now you need clone through the ssh through the https protocol okay if you want to clone it using ssh protocol with this one it's going to ask you to generate public private keys on that server as well it's a little bit complicated thing so let's just copy through https okay and i'm going to call this api the same name api your surveys dot xyz okay hit enter on that it's gonna start cloning if your repository is private it will ask you for username and password as well and you have to provide now we have that api your surveys.xyz now we need to navigate inside the folder oops and we see all the laravel files and folders right here we don't see a vendor folder because vendor is installed after we want run composer install so we need to run composer install right here it's going to take a couple of seconds to install everything i'm going to pause the recording and get back when this is done quick hint putty also has possibility to duplicate duplicate an existing session so right click on the header and click on duplicate session and it's going to start new session and you're already authorized because you specified your public keys now we can go in the domains api your service dot xyz and we can do something else we don't need to wait until the composer install is actually done so i'm gonna type ls-la the vendor folder will already be created but it's not the install is not finished yet what we can do is we can create dot en file okay on the left side this one has already finished okay so i'm going to actually close this i don't want to turn terminals at the moment let's clear up and now i want to copy using cp command en dot example into en file okay now we need to edit our eno file and i'm going to use nano for this because it's easy en dot nano.ian and now we have that opened now we need to change the application name and i'm going to call this let's put in the double quotations that's survey manager or something like this so that's your application name the environment is in this case prod it's a production environment we need to generate api key as well so we're going to run an artisan command for that we need to disable debug of course so we need to set this into false what's the up url that's going to be https api your surveys dot x y z that's the application url okay log channels text so we can leave others by default we need to specify connection for mysql for this let's go in the hostinger h panel let's on the left side we need to find a database section and click on mysql databases right now we have only one database that's for another project we need to create now new one and i'm going to call this your surveys um let's just call this your service okay the username will be the same the password i'm going to generate oops i'm going to generate now new password for that or i can specify whatever i want if you on the right side we have that button generate password i'm going to get this and open the protein and i'm going to put this right here let's put this in the double quotations to make sure that it works okay i'm going to specify what's the database name we specified the database name to be your surveys but we need to grab the whole thing so let's actually create this okay database was created successfully this is the database so this is the database i'm going to get this and paste right here the username oops the username i think is the same thing but let's actually copy and paste right here and the host and port i think it's a local host and the port will be default port okay you don't need to configure anything else right now just click control o on your keyboard and then enter and then ctrl x to exceed from here okay we created our en file we run composer install and now we need to run php artisan key generate dash dash and si okay application key set successfully now we can open en with nano again and see right here we have the up key we can close this using control and x and now the last thing we need to do is to run migrations i think so php artisan migrate now migrations were successfully run now we can try to access api your service dot xyz and we see the page is lost so why is that because in the hostinger age panel in the file manager if we just refresh these we see a lot of folders but we don't see public html hostinger looks for public html folder right here and that's going to be the folder which will be served okay we don't have public html but we have public folder and inside the public we have index.php so if our public folder would be named public html hostinger would read that and make it working however if we just rename public into public html that's not going to work because laravel application will be broken laravel expects public but the hostinger expects public html how we're going to do that so actually we're going to have both using symbolic links so again we are we type pwd we are in the api your service dot xyz folder i'm going to type ls la and we see public folder right here now i'm going to type ln s and i'm going to specify right here public i want to make a symbolic link of public into public html okay we hit enter on that now we type ls ls again and now we see we see public html which corresponds to public and if we open and refresh in the file manager of hostinger we see right here that symbolic link well it indicates that public corresponds to public but that's actually not quite true we see this using ssh now if we open api your service dot xyz and reload we see laravel's welcome page which is awesome now let's go in our login page actually we need to register so i'm going to type specify the information i'm going to type incorrect password let's open the network to observe and click sign up now the api connection is successfully done we get the password confirmation we get the basically validation errors now if i specify correct password hit sign up i am logged in inside the system however we have an error and what's the error image url so that error basically happens because we try to get the data and the data the latest survey is null and on the dashboard we don't handle the scenario when the latest survey is not okay that's our bug of our code we can fix that but the application is actually deployed and working okay so if we go in the survey section click add new survey and let's call this test1 we can choose an image this one and let's give it some lorem ipsum let's give it some expired date as well hit on active add couple of questions test one save that okay survey was successfully updated that actually should be created but anyway the service was actually created if i go on the dashboard now i see the dashboard is working okay because now we have that survey if we go in the surveys page of course we're gonna see that and when we click on that public link now we have an error something is actually wrong and why is that happening because we are using history mode for navigation for our view application and we need to have a proper rewrite even if we just copy and paste or just refresh this page we will see not found okay when we try to access the root domain then it works and navigating works fine but as soon as we reload we lost everything okay this is something we need to take care of and handle let's actually close the api your service xyz file manager and we're going to go into hosting section but in this case inside your server is.xyz now let's go in the file manager and we we have to make some changes inside the public html folder let's open this right here i'm going to create new file and call this htaccess which is the apache configuration file for local folder okay i'm going to open that and right here i'm going to write rewrite engine to be turned on so we are turning on the rewrite engine and we need to write the following rewrite conditions if the request file name is not a file so whatever comes in the url if that's not a file and if that's not a directory we need to redirect to index.html so if the request file name comes on css or javascript file or image and that file exists it's gonna just reserve that file otherwise it's gonna redirect everything to index.html okay we need to save this and now let's have a look so if i just reload this it's gonna start working okay and let's close this and if we click that link right now it's gonna start working as well okay so i'm going to type some test answer right here click on submit we we got the response go in the application go on the dashboard and now we see one answer and the survey has one answer as well so everything works so far so we have registration sign up and dashboard and everything and of course we're gonna have pagination as well but i'm not gonna go ahead and create 20 surveys next time if you want to upload a new version of front-end vue.js so you can delete everything like assets favicon index.html but don't delete hd access you're gonna need that okay so just delete everything and re-upload the whole folder that's the end of this video and i hope you enjoyed it if you feel that this video was a little bit of helpful for you just give it a like that helps youtube algorithm a lot and that's going to promote my video and offer it to others you're gonna find the source code in the video description also i'm gonna put in the video description the survey which is from the application we just built if you have one additional minute please complete that survey we don't have possibility to see answers yet full answers i mean but we're gonna do that in the next next series and you're gonna see your answer somewhere right there well it's not gonna be your answer because you're not gonna enter your name or something it's anonymous but somewhere there will be your answer like which you have failed you get the idea
Info
Channel: The Codeholic
Views: 393,384
Rating: undefined out of 5
Keywords: TheCodeholic, laravel full project, laravel full stack, vue 3, laravel vue, laravel vue authentication, laravel vue full project, laravel vue full stack, Laravel Full Stack App, Vue 3 tutorial, vue 3 laravel 8, vue 3 tailwind, vue tailwind project, vue 3 project, vue 3 tailwind css, vue 3 tailwind tutorial, laravel tailwind css, Vue js full stack app, vue js laravel full stack app, Laravel 8 full stack app, laravel, laravel vue js, vuejs laravel, full stack vue
Id: WLQDpY7lOLg
Channel Id: undefined
Length: 318min 44sec (19124 seconds)
Published: Tue Jan 18 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.