Building a Web Application in TypeScript with NodeJS and React

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to look.gg this is my new website that i started building four days ago and i built this as an example of what i can do an example of what you can use to build a complex web i put all the code online on my profile repository and you can download this and it's great start for building a new website so i suggest downloading it installing it and i'm going to use this video to explain how i built it what's in there and so let's go over it now we got these pages career cooking messenger meeting i made these up just to be able to get all these apis implemented and of course if you're starting a new project and one of these might be interesting to you you can just take it and strip the rest out of the app and use that so let's go over the pages and maybe you'll find something that you could actually use so career is one of the pages we've got an api call to github where i get all my contributions that i've made since 2011. here you see the total and here you see a calendar filled with it very beautiful very nice to use and at the bottom we've got a google maps implementation with markers and there you can click on things to you know get extra information on that particular marker marker another really interesting piece and also pretty well not difficult but a tricky thing to implement so that's the career page then we got the cooking page this is a page that's just meant to be like a list page i took cooking as an example because it was easy for me to do and nice to have a website as well to have some references to some good recipes i only added three so far and it got sorting so you can change sorting change what you're sorting on and the direction you're sorting on and you can also log in i'm logged in right now and then you can create a new one you can create a new recipe and here you can see it starts up you can say hello and here's some ingredients and then you can change the difficulty how long it took and you can also upload a file immediately let's take these potatoes bom and this goes to aws s3 so this is a direct upload to s3 does not go past the server but the server does generate a pre-signed url which is useful for kind of security kind of making sure people only upload what you expect them to upload and you can put all kinds of uh restrictions on there through the aws sdk so uh this is markdown by the way this text so um meaning that it follows the markdown rules on how to write down uh how to generate html like it turns from this text to this dynamically and this is basically what's being saved in a string in the back end so that's how it works and then of course you can save it and then i've got my test now here hi ingredients and i can also edit it again and then delete it so that's a good list and uh the recipes like it says here the recipes you create are only visible to you so that's uh well not really a security thing but more of a useful thing for me in case people start uploading weird stuff all right so and then you got a filter here as well so that's that page for lists and i'll show you how to implement this soon messenger this is an interesting page because now you see that i got a select message from the luc.g bot where it says that luke a user arrived on the page it doesn't know who i am i mean i could add that because i technically do know who i am but this page is also usable when you're signed out and here i can so first of all let me show you we got the message right here so now i can not this one but here and now i can type hi and here you see that this message is coming from the user and i can type back i can say hello and it pops up here so these two are connected and this is a great way for your business or your personal website like in my case to be connected with the messenger app to um yeah get notifications and quickly talk to your people and people might expect that this is a bot that's the more common use case and you could do that too but in this case you're just talking to a person which is very useful and it's a very simple implementation so i'll show that to this uses web sockets in the back end and of course the slack api and it's a very simple screen just some time and and the message itself and the user is always this orange white guy so super basic very clean try to keep it very simple and now the meeting page this is a very interesting page by the way it also says when the user left the page which i thought was good because then you know that you can stop talking all right so this page is interesting because it uses the twilio api and what happens if i copy this link here you say meeting room equals this and if i copy it and go here and allow my webcam to be used there you go now now i can leave and um interesting thing here it uses webrtc in the background so this is actually free to use for the twilio api if you create the go type room which you can configure it uses webrtc which basically means that the video is being sent directly from your computer to their computer and from their computer to your computer and there is a little bit of a protocol in the middle of webrtc uh which twilio configures for you so it's very hands off and it allows you to get a feature like this uh into your website and you can because it's free you can basically open it up to anyone as long as it's a one to one conversation it's uh it's completely possible to do it for free if you want more than that you're gonna have to start paying twilio although the prices are pretty good quite affordable i believe so yeah these are the pages that i have on my web page right now and now it's time to dive into the code and see how it works right because first of all even if you don't like any of those features you want to build something completely different the setup that i have here is very clean and i recommend it it's typescript so uh i'll get to that it's basically javascript with types and i'll get over that but now first the client so client is built in react okay so we can go to the package.json here and go over the dependencies see if there's anything weird going on we've got phone source which just you know i got use open sun's font and send for the logo so these are just some fonts that i insert and this is a very nice module ford awesome font free so these are all these icons and they're all free to use and it's very simple to implement so definitely font awesome has has been a great way to do this redox gs which is a method of storing your data and i can show you in detail what that looks like here it is and this is right now my state i can even show it in another way let's see i think the chart here you can see the the data that is in my system and there's a lot of messages here actually these are the git updates maybe i can close them these are all my contributions that the api loaded so let's go more to a more more normal view here json view you can see the user i'm signed in who i am my email address whether our email is verified this is all coming from google that's that google sign in oh i guess i should show you that so i can log out and sign in again and i can select my email and i'm back and the system knows who i am and put a cookie so that if i refresh i'm still signed it so those are all features that are super useful now let's go back user nice we've got slack which tells me whether i'm online or not and whether so that's me luke right not the user but the one owning the website is online or not and the messages are put in here twilio which is nothing but a token right now all the system really needs token the room name gets generated identity two but we'll get to that github which is uh well right now it's empty but if i go to the career page it fills up with the api request you can see the request coming in here so that's what redux is it it saves all this data puts it in the right place for me to easily access it throughout my other components and implement it into the website and here here are the default recipes that are always visible not mine those are not loaded in but these are just the defaults that i have put in constants so not the ones from your account but the default ones and you can see here that it's very simple like you you've got an image you got it's just a couple of basic uh properties and obviously for your list that you're implementing which might not be related to cooking you might have other properties and you can easily change this so that's why the system is very easy to use so that's that then of course we got google maps implementation these are just the types so for typescript uh very often you want to install the separate module for types if it's not part of the main one already so you can see this over and over again here you can see google maps react three egg dome reactor redux and router dome to all use the the type definitions uh loaded from a separate repo so you definitely need to install that but again it comes with this with this repo when you copy it so definitely keep those in there those are very quarter making this app run any app basically if you're using react um then bootstrap so i use both bootstrap and react bootstrap and this is very good for getting a cross browser compatible styling situation where you get some default css already applied to various things and also you get this amazing here let me show you an example let's see so here for instance is a modal modal react bootstrap model what you saw when i was on the cooking page and i was uh for instance deleting one it has this confirmation are you sure this is directly from bootstrap so these kind of features and also the buttons are bootstrap there's a lot of bootstrap in this page which helps you just create with very few lines of code quite precise looking interfaces and of course you can still easily change anything in any way you want because you get the direct scss to overwrite so you're not really power is not really taken away from you but there are just some good defaults being set by react bootstrap so back to the package we got date functions state fns uh so this is very useful data venus i use all over to parse uh json for instance to go from a string to a date object um so that's a great way to use it uh there's also let's see i also do some formatting here so you can take a date object turn it back into a string based on your format so another great library to use and let's have a look i use this both on the server and on the client and that's the case with all the uh agnostic agnostic dependencies nano id is the same so when i generate an id i need to generate long id that's unique that i can guarantee is unique then i can use nano id which i'm using the front end for the twilio creating the room and identity and in the back end as well so um then we got of course react react bootstrap i talked about react dom which is needed to basically start up react to initialize it uh markdown which is that what i showed you in the cooking page where you can have that text that transforms into nicer looking like list elements and azure elements that you can style redux which is again what i already talked about although again i use the redux js toolkit together with redux because this is more of an addition to it and i'll show you why this is so nice a bit later down the road react router dome very useful this is extremely powerful this allows you to uh get this nice uh well i'll show you the um the general architecture for your um for your pages so here you can see that there's a switch from react router dom and a route and so you can say this is my these are my pages that i have and only it goes from top to bottom and the first one that matches it goes to right so at the bottom you always put the router the last route and below that you put a redirect to that route and that way you have a very clean redirect system pure front-end everything front-end and then the other pages go above and you can also match multiple paths you can put ids in here like if you want there's all kinds of fancy stuff you can do but again i've implemented it last four days as simple as i could as fast as i could hopefully this can be useful to you um so that's react router dom very useful and there's more stuff that i need to show you later about what to do with uh route parameters and um url uh query but okay we'll get to that react scripts so this is a cra this is a way to start up your app so you can see cra running here uh you just in this case i just do npm start but you can see that start runs react scripts start so that's that react scripts part and it's great because it has these uh default uh like if i make a change it automatically refreshes like it basically helps you with development uh and sets everything up for you and also builds your app when you're done when you build it everything gets turned into javascript i think version 3 and then you can deploy it on your website in this case it's actually super easy what i've done here the api also hosts the client so it's a very simple system technically you could also put this whole website on another host and then still connect to the api i put them on two separate domains in my case luc.gg for the main website api.look.gg for the api so you could easily split them but i actually routed with my with my routing in aws i routed both of these domains to the same server and then the server decides um what to show and i'll get to that when i show you the server okay so we now have gone over uh well have we gone over everything yet let's see twilio twilio video well that's just a plug into uh dependency to make the uh video work video sharing work with webrtc and typescript obviously because that's how the whole thing is written the whole thing is written in typescript so that's what i use okay and then here we got some quick settings for eslint printer which is super useful i definitely recommend installing that extension into your code editor because it allows you to quickly do a shortcut and clean up your code kind of always never never write dirty code that has weird indentations or double quotes where you want single ones and of course you can change the configuration of this how you want browser list helps with production build and you just basically define how you want it to run what you want to optimize for and i just these are just default settings you know perfectly fine to use even in the production setting these are perfect so again i do this professionally so even if you do this as an amateur i would still recommend sticking to all of this and just just going along it's very good setup so here are the types installed for nodes so i can access the process and things like that node sas to convert my scss to css and then some prettier config files for eslint prettier itself which again works together with my extension in my in my code editor dev tools which is the thing i showed you here and the source map explorer perfect okay so uh wonderful this is all the dependencies i have in the system now we've talked enough about dependencies we can dive into the page right so let's go and actually look at this code generally every page i have the first thing i do is import the scss here you can see the scss i also have a rule that for the component that i'm writing for i write it with a capital that is kind of a little unusual for scss or i mean css to do this but in this case it creates this really uh structured approach to building components uh so i definitely like it and you can easily see the difference between a component and the objects inside of the component and i always scope it like this so okay so scss as you know it i mean as i hope you know you can put selectors inside of selectors to automatically generate css that actually uh scopes them correctly so this this app would be repeated for here anyway you don't need to know that what you need to know is that of course this a selects all the a's inside of the app for instance okay so uh here you can see my phones being loaded a specific weights font weights that i want and here is the icon set that i use okay so what can i say well i use a lot of flexbox flexbox is a great system it's um i'll show you a little bit about the power of flexbox so for instance uh aligning things vertically is really the the biggest strength of of this system you can see that i said line item center so normally they're there on top right and then i want them centered and automatically works it's very nice align items great one here i say for instance justify content flex and meaning go to the right if i remove this flex start on this case it's actually the margin here that's doing it so i have to first disable this margin margin right auto which pushes everything away but in this case now i can say here flex end for instance everything goes to the right flex start everything goes to the left in this case i can kind of remove that line because afterwards i decided to shove the low i mean later i implemented the logo and when i implemented the logo i i of course did margin right auto to make it the only thing on here so this would work both ways anyway so margin right also great trick if you have one thing that goes away and the other wants to stay together you just use a margin auto you can even put it here and push to the left or put it on the left when i push to the right but of course since this is my kind of exceptional a-link anchor link and it already has a separate separate class name logo i use that selector here to push things to the side okay so we've got this beautiful basic setup very simple now let's go to the simplest page i have in my system right the dashboard the dashboard is literally nothing but text and links so here with a default functional component that's what fc means this is the simplest one you can make because there's nothing going on here on the top there's just instantly a return with the elements that i want to show and there's no refresh there's nothing it's just text and styling and let's look at the styling and see if i'm doing anything special nothing special here 62 lines of code we got display flex as always there's a flex direction which changes make sure that everything in the system goes from everything in this page goes from top to bottom as you can see it doesn't go from left to right which is the default direction so that's why i put it on the column mode and then the internal things well we can go over exactly how to style things but important thing here is just to use display flex learn what it does because it's the most important innovation in css in a long long time and i remember doing it before flexbox and i can tell you especially vertical alignment it's impossible so definitely learn that and then of course we've got all kinds of fancy tricks down further in the page but this page is not fancy at all this is the most basic you can see something interesting here where i use i i use rgba lot which is a nice trick to make something fade out a little bit on the background the a stands for alpha or opacity so this is only 20 visible so you don't need to change the opacity of the entire block you just want to change the background which i do here and here here in these blocks everywhere okay so that's a great trick now let's go to the first page where we actually do something the github career page so github github github well there's actually two components that relate to this the google maps i put in its own component we'll get to that later and the first one is career and career imports the google map and puts it at the bottom okay so first of all you see that with data for date functions i import a whole ton of things for this calendar right we want all kinds of calculations we want to add subtract everything for this page so let's let's see how i did that like um we've got let's see first let me not scroll too fast so we got this top here which is very important this is before you start returning so this is your controllers these are this is the place where you um write effects and other hooks and do all kinds of fancy stuff and then you just return at the bottom you always return the actual components you want to render and you can use these variables down in there so first you see that i use query and set query and that this is a hook i wrote myself the use query hook and if you don't know what a hook is um well uh it's basically a piece of code controller that you might want to reuse and this is definitely reused a lot i put comments everywhere to try and help you out if you're if you're not looking at this video and you're you know you're just on your own with the code then hopefully you can make sense of it still but here you can see another piece of power of the react router dom i you have to use history and use location which are the hooks that they export so um then what i do is um i'll double click location so you can see first thing i do is i i generate this query object right we have two things in this in this whole module we have set query and query and query what that is is if i go here to the left you can see here this question mark date equals something right like a date actually it's only the year and the month and this is the query so the query date is this value right now and i can automatically get that value through here i start a url search params which is a browser api and i shove inside this string which is exactly this thing here and it can get more complex like you can see that here i can you know here i see sort created direction asc for instance right so it's relatively complex you can put all kinds of stuff in here it can get as long as you like and then you turn it into query i loop over it put it in an object and give it back and now the first hook i want to explain is use memo which is a react hook very core used all the time because what i want you to understand about react in case you don't know is that this thing like this function can execute all the time but what you don't want is this object this query object or this set query object to be new to be different to be updated and you use use memo to kind of info to do this to enforce this so use memo use is kind of use memory i guess technically i think could also be something else anyway it doesn't matter how it works is that you generate something here you return the object at the end and inside these brackets you write down when you want this function to be re-executed and this property to be re-returned for this thing to be updated so if i say whenever the location search changes so for instance somebody clicks on this button right because the search here changes then we will calculate this again right so it doesn't happen all the time it only happens when that event occurs so this is this is good is a good way of saving performance and keeping your website from going slow which is actually very easy to do with react you have to be very careful and try to avoid wasted cpu cycles so here there's another way to do it with use callback is the same principle but instead of returning instead of returning a object any object this is for functions because now you can say okay so set query is a function and this function takes an update parameter in this case and the second one is options so an update and options those are the two variables that i mean the two arguments that this function takes set query and update is an object itself with strings as keys and a number string or undefined as the as the values and i'll show you an example of how i actually use this because that might might look a bit easier here you can see that on click so if i click on the chevron to the left which is this button right here if i click on it then set query date i that means so here i i have the first argument i don't give an options argument i just give the first argument and i say that this is an object of course and in that object i just put one property date and then i format the date that i want to show with like i showed you the year and the month which you can see here right so i just say hey update the query to do this that's it very simple set query so again using hooks and use query hook very simple to work with those parameters everything after that question mark and to to read them and to also set them and you can also unset them by giving it an empty value so you can say a date and an empty string or undefined and then it will become an empty value in the query parameter actually it will be removed from the query parameter so it won't even leave the property which is something also that my function does which is very useful i guess i'll show you even though it might here so push or replace the current url with new parameters and loops over them but now here you can see that if there is an update key if that exists then i will update it but if it doesn't exist i will delete it from the object itself and then later when i when i replace the url using history which is that use history uh hook from react dom i say that the path name stays exactly the same that we already had i'm just updating the search with these new search parameters and to string right so this is the the default system to to update these parameters okay well that was a lot for such a simple feature i'm sorry let's continue uh it doesn't get any better because now we're going to have the first hook that actually connects to the api the use github hook but it's a very nice hook and i really recommend it it uses the fetch api so a bunch of people install all kinds of plugins to make requests http request but i i strongly advise against it the default new api well not even that new it's pretty old by now a fetch api is very useful and very simple to use so let's show me let's show it okay use github now i want to show you the piece where we fetch first right because this is the most important part here very simple very simple you can see the special await keyword which is only usable because we're working in an async function so you have to put that word async in front of a function to do it it means asynchronous and it basically means that we're able to to let the script first finish this fetch before going to this line right that's what weight does so it's a very very important keyword to remember okay so we say await fetch we fetch this from our github endpoint on the server and um we have this special thing called a signal and signal is useful for if you want to stop your api from being requested over and over again if i go to this page really quickly and imagine that this response would be a bit slower i guess you don't want to keep spamming your api with new requests all the time and what i do here is i say okay this signal is a new board controller which i shove into my abort current reference that's another hook use ref i'll talk about that later because it's very important but use ref is global to this github hook so if if gita if this github hook is doing multiple get contributions over and over like when the user is is spamming well in this case it wouldn't be switching page because you would get a new instance of the hook but imagine that you're using this api call multiple times in one page then you can basically abort the previous one and that's what this line does afford the previous get contribution request if it existed right if this signal is there we can abort it and then we create a new one save it on the same place so that the next one can be imported too and then we shove this signal into the request but okay you can actually remove this variable and completely not write any of this it is fine this is only if you want to do an optimization to how you fetch your affect your data um that you want to sometimes stop the request while still going there's a lot of bugs actually where people do this kind of thing where they request some data which might take a while and meanwhile the user is doing other stuff and then when it comes back suddenly the interface bugs out or does something weird that they don't expect because well they didn't abort the request when they left the page right that that is possible so you gotta you know there's a good way to solve that which is to have an abort controller now the method is get which is also the default but i still explicitly stated it here and the headers which in my api is always the same as always content type json i only use application json the only thing i ever write okay so now we can also say here if the signal was aborted right then we will stop here and we will return a border true to whoever was using this function i also have a loading state which again is the use state hook we use a lot of states here so again very simple loading set loading starts off being false and every time i say set loading this thing changes too very simple right so and here i say set loading first i said loading true in the beginning and loading false after okay then we got loading is stopped we got the fetch it was not aborted so we have the response now i will turn it into an object and await rest json turns that json code into javascript object which is of course critical we need this object right this is also why we're putting this whole thing in the try catch block here you can see the try and here you can see the catch is because we're doing both a weight fetch which doesn't work if your internet is disconnected and throws an error so we want to catch that but most importantly we want to catch this if the data that we get from the api is somehow incorrect and doesn't work we don't want to crash the browser we just want to recognize that and display an error right so response is a waitress json now we have an object in here and then we check with that object we check uh what's going on here because we want to know if the status of the request if the api returned something in the 200 range now i can show you the request itself by just refreshing network tick and we want to show all the xhr requests and here you can see the github request right actually i can clear this and show you that when i refresh there's one github request there now you can see in the headers this is a 200 okay status code right which is perfect so if it's if it's higher than 300 or sorry if it's 300 or higher then we will dispatch an error because 300s are used for redirects which i don't use in my api so it would actually be strange if it was like that 400 are client errors and 500s are server errors that is the rule or actually the standard uh in http language http code protocol and so we only want something in the 200 ranges we don't care about everything else so if it's above that throw the error show it in a modal and we're done this should never happen honestly but okay now we got the data we know it went through correctly we fetched it we complete everything is basically done we got it right and now i dispatch an action to my store which is this is the redux part where i set the memory system to add github and then the response so it started off being an empty object right you can actually go to the store to show you this is my store and this is the initial state of that store this is not store.ts right here and by default github has total zero contribution is an empty object and then when we get this data it has total a certain number and a big objective contributions where it's a date and then the number of contributions i made on that date perfect so we got it saved and now that's it set loading is false when you have an error that's it perfect so now we've explained this whole hook and how it works and we can go back to the career page and there we go okay so total contributions we've received those now with the use selector hook another hook that's interesting to explain uh store exports at the bottom here a use selector hook and with this hook you can basically write down it's a function you execute it and you give it a function in its first argument and here you get the state right and in that state you just select what you want and that comes into your main loop right so in this case i said give me the github give me all the github properties in this case contributions in total and then here i instead of just putting it on a variable you can use this special notation to already deconstruct the variable github into total and contributions and those two those two variables i can then use down in my code um okay so that's the use selector super useful you're going to see this all over the place and by the way all these hooks i'm i'm going over them very slowly now but you'll see that this keeps being reused so i won't have to explain the other ones so i'll just rush over all the novelty things that i see that i haven't explained before um okay so query date this is the thing where i want to know what i'm currently supposed to look at right and if there is a query date that means somebody clicked here here then i i need to find out what he what he wants to look at which month which i do i say parse iso which is another um what's called another function from date fm and i i put in the year and the month and then i add the date and i parse it and then i get a real date object back and if nothing was selected then i take the current date the new and this is exactly down to this millisecond but right i just want to have this moment right now which is why by default when you load the career page you see march 2021 because of this new date okay so then i want to know what is the start of this week and then what first of all what's the start of this month right so that's actually number one and because sometimes here let me go to another month sometimes you get this case where the first of this month is on friday and then the calendar is supposed to show things from monday right so i say start month first and then surround i also say that the week starts on monday because the default is actually that it starts on sunday americans but uh so yeah we're gonna do uh week starts on monday uh european style and then we take the start of the week and then we get this 28th here for instance so that's how i know the beginning and i do the same for the end end of the week end of the month so i then i have the the left most day and the rightmost day um and then i want to know the difference between those days in days and then i get the amount that i have to loop okay so all right let's let's show a little bit oh first of all uh here you can see that hook being used to get contributions you get from the use github right now i have an effect an effect executes whenever anything changes inside of here right so almost like the use memo but it doesn't return anything in this case it just it's just an effect okay so i say whenever get contributions itself changes which it never does this this doesn't change get contributions is an unchanged object so this only executes once when this object loads so when loading the page then this effect goes off and we ask for all uh contributions to be received okay very basic then i say if loading uh which is that other property that we got from github right that that that state that i was referring to before let me go to it use github this one right that one is exported at the bottom so i can reuse it in this place in the career page uh and if it is then i'm only gonna show a spinner it's actually very quick if i refresh you can quickly see it there you see it like pop up real quick that's it so um that's this piece of code that say if it's loading then just show a spinner when it's downloading we're going to show the entire page so now this is the page i already explained this on click handler here where we have the set query and here is where i format the number that i get from the api the total and show it and then here is where the fun starts for the showing the calendar right if you want to have a calendar on your website this piece of code is very clean i mean i believe so and you can use it so i loop over the weekdays monday to sunday right so i just say give me a new array i fill fill it with nulls so that i can map over it if you don't do this the map won't execute a single time you need to fill it so i fill it with nothing it doesn't matter and i'm just doing underscore here because i'm not using that value i'm just using the index property which starts with zero and ends with six right because that's a total of seven so now this is a number that goes from zero to six and repeats itself and then i put the divs in here and i say hey give me a new date 2018 january 0 means the first month so it's january and then i add the reason i picked 2018 i remember is because that was the day where the mondays perfectly align with the first is the monday so that's that's why i picked it um and then i turned it into a format where i showed the date all right so perfect um this generates that now we need to go to um this part where i will make a new array and i'll i'll divide the days by 7 and then seal it right meaning that seal means that even if it's like 5.1 it becomes six right it rounds up that's what cl does math seal and of course that's the case because i want to know how many weeks am i supposed to show uh in this calendar um so that is the uh and and if it's if it's like this case where i'm on the first then i still want to show it although i need to know that i need to render this this block and this block so basically calculate this fill it with nulls again and then we have the week index which week we're rendering and we're starting from zero zero one two three four that's a week um okay so i repeat that and then within it i go and i loop seven times because i know a weaker seven days and i start with the start time which i calculated in the beginning right that start of week start of month and i add um the weekdays times seven the week index times 7 plus the day index so this gets you the day that i'm supposed to render then i get the date by just taking this calculated day and giving it a format and also i want to know whether we're in the current month or not because when i'm outside of this current month it gets slightly more grayish you see that this is a little bit more grayish than these ones because i put an extra class on there which is not current month some calendars want this to be even more pronounced or want to have separate like that you only highlight the current month in the calendar so that's why i have that there and then i take the contributions i look at that date that i'm looking right that that how many contributions i've done that day and if it's not if it is undefined i don't write anything but if it is um this is by the way i'm writing in the class name right now so i'm saying that in the class name i will say the word level dash and then depending on the amount of contributions a number so let's have a look right so here's level zero level one level two and i i only have a couple levels i think maybe four still two let's have a look uh i take the contributions date and if it's over 15 then i'm gonna kept it at 15 and else i'm taking it directly and then i'm dividing it by three right so that that gives me the that's like little calculation i use to get the level um so i don't have to style each individual like one two three four five like i only have a couple levels and that's it if you're going over a certain amount you got a bright yellow i mean bright green situation like this one 16 the same 17 is the same as 32 because you're capped at 15. okay so uh now we use oh this is very important of course when you loop when you create a loop like this and you're generating with a map you're generating multiple divs you want to always write a key and in this case i always use the key being the index in there and this is for react to know how to update this list and stuff and it will throw errors if you don't so if you want to keep your console clean with no errors you need to do this always and it can actually also render wrong if you don't so it's quite important okay so and then of course we have in the little right corner we have the the day right so that's this thing and then whether we have contributions or not if we have contributions then i will show how many and a little text and then i have this s being optional where only if uh if the number is one i i don't show it so if it's not one i do show it and here you can see another thing i often do is where i i say that the date equals one and then i say and and right like or i mean ampersand ampersand which means and um and i do this because in javascript at least this evaluates to only this value so if this is true then it will render this and if this is false then it will render nothing it'll render i think it's false which react interprets as nothing so very straightforward way to do it and works very nicely because sometimes you see me in inside of strings for instance i use the ternary notation where i say this is the condition question mark is that is their condition true or not if it is then this if it's not then this which is nice but and inside of a string i do this right because here you can see i'm inside of the string so i'm here so i have to do it but if i'm not if i'm in react then you don't need to do don't need to do that if your other argument is empty you can just uh do it with the and instead it's a bit cleaner so i definitely recommend that perfect so now we've gone over how to render a complex page like this how to use a bunch of hooks and i use date functions and effects and all kinds of fancy stuff so now let's take a look at another fancy part google maps google maps is interesting because this is something that google the maps developers themselves have as well you should never initialize google map more than once on your page so it should initialize once load once and then be done that's it and in the beginning when you load your dashboard you don't want to load google maps right now right you don't want to load all that code in fact they don't even i don't think they even allow you to load the code locally or at least it's kind of difficult they want you to use it dynamically to load it from their api and i'll show you how where i do this this is where i do it i load the script it's called lazy loading right this is when here and lazy load the google maps javascript library so i only load it when i need it lazily i don't do it proactively i'm not an active guy i'm a lazy dude i'm gonna only load it if i really need to and um and so i'll let me show you like we can click on javascript here go to the career page and boom you see that there's a bunch of extra javascript loading in from google maps right and the thing is here i'll clear this and i'll go up and down and you see it doesn't happen again it only happens once which is the special thing with google maps in fact the entire map is never removed after i render it i just hide it um here you can see that right if the component unloads then we will hide the google map container so the container is not really even part of react it's kind of something outside of it because google doesn't understand react i mean they don't their their library doesn't need to know how to interact react uh it just renders dom events like it's it's it's more basic so to speak so with react you kind of need to work with it and i'll explain how i use it right how i work with it here i create a reference which is basically just something that you know references are things that always have the property current inside of them current here you can see another one current and um they are not tracked by react so if this current changes react will not re-render or do anything because it is not even aware of it right like and there's a single reference as well so even if if you use things multiple times this reference will stay the same anyway you'll see that more later so in the beginning i say that the map ref is null map ref.current i mean is null but when i give it uh it will be an html div element right that i already explained that here in my types so let's see where we set it right like boom here we set it here we have a layout effect and a layout effect is another one of those hooks very interesting so a use effect happens before the interface is rendered a used layout effect happens after the interface is rendered that's an interesting difference between those two effects anyway it doesn't really matter in this case because we're just gonna have a map ref current if it's not found meaning it's null then we need to find it right so we're just going to use a good old basic default hardcore document query selected google map container and in the beginning when you arrive on this page for the first time you've never entered this page this will also not be found right so if it's not found then we're finally going to create it we're going to create a new document create element very programmatically right very old school this is raw dom operations but it's very useful in this case because we don't want react to do any fancy work around google maps this has to be outside of react react has to work with it but not be responsible for creating or updating these properties so we're just doing it old school style manually this is how i actually used to do it all the time so it's not that weird for me create an element diff then to add to the class list google map container class is actually super new but anyway it works and we also have compilers that in this setup in this setup i'm giving you this this repository it automatically translates this to a better version that is more proof for browsers that don't have things like this there's automatic polyfills in here anyway it doesn't matter so um we add the google map container class and then we append it to the body so to the body now remember in this app to show you these elements everything is happening inside of root that's where react takes over so to speak and then inside of app is my first root object that i myself wrote and inside of there everything happens right and main then renders career and it's all nested okay but if i then put something in on the side here you can see the google map container right so it's it's completely outside of the rest of the system which is exactly what i wanted right um now i've now added the google map container okay imagine i've just added it um and well ignore this for now because right now it's already visible but we just want to show that containers what i'm saying and then we're going to say if the window init map doesn't already exist which is a global function that we define we will define it and we will load it but remember now that i've done this no matter where you go on the website this will always stay defined because it's a global so window.init map will always be there and this script will also have been loaded and will stay there right so you're not changing the google map you're not even removing it you're just hiding it you're just doing this once and not again so that's how it loads this library and also this key is very important and comes straight out of your react app google maps key variable i've made um i can't show you the keys of everything well actually for the front end i can but for the back end i definitely cannot because that would be a security leak um but i made end tilt examples to show you how it's done right so in this case you can see that we got a production api that you should fill in and a google maps key that you should generate and you can just go to google cloud console and generate one it's super easy to create a project there and to add a key and then you can have your own google maps card and there's also aws implementation for that uploading that i spoke about and for that you need to know the bucket name in this case actually well doesn't matter i use it for something else but doesn't matter it's very useful but the backend has many many more actually i'll show you what how many to back at that the backend is a serious and file bam right aws key aws secret bucket region cookies i mean there's a bunch to talk about in the back and let's not let's not even get there right now we're gonna stay where we are this is a long video there's a lot of talking i need to drink more i guess um okay where were we google maps boom all right so now with this layout effect something interesting happening here um i'm saying that when this unloads like this how effects work right inside of an effect you can return a function which will execute when the component unloads or actually whenever this changes and the previous instance unloads right so and in this case what i want then is for this thing to be hidden so i add the classlist hide and in the beginning you saw that i removed it so whenever this this effect starts up i i remove the hide and if someone leaves the page then i hide it again so this whole thing about google maps is never really going away it's just being hidden with css this is a css class name okay now and then the only thing i actually show and react in this component is a google map itself is a little employment history so this this little bar here that's react and then right below that is my google maps all right and this will depend on how you position your your map okay very good now we've discussed all of the career page now every single part which was very interesting very nice ah i guess one thing i should maybe that i kind of went over too quickly is this uh this middle part here in it map so again this is the function that gets attached to the window object and um is executed only once by google itself and you can actually see that because here you can see callback equals initmap meaning when you load look into the window and find the method with this name and execute it that's how google maps wants you to work with it that's how they want the callback to be done a very old school way of doing it actually so that's how i did it right i in it mapped it and i put it in the window and then they can execute it and now this google map when i started off i say where to go how to zoom and that it should use the map ref current diff that i already inserted into the page before i loaded the script so now this can be used this can be used to load the map and then i have this little window that's the thing you're looking at when you click on those markers and then i go over the markers and i want to show you where these markers come from because this is in my constants file and my constants file is filled with again constants things that don't change that keep being reused over and over again and these markers are one of them they're not part of memory not part of my store because they're static nobody is able to change them they're just hard-coded values so to speak so that's why i put them here and a title and then a position where i want the marker to be drawn and then the content again this is they want it in html i can't put this as part of react because again it's google maps they decide how their api works and they want it like this so that's how i do it you give them the content in the string format of html code but it's very basic html and of course you can style this which i did um yeah and here you got my whole resume basically well not all of it i just put the key once with nice positions because then you can look at the map and see that i worked all over the place anyway um back to the markers okay and then here one thing i do is if i created a marker which is index zero the first one which is my most recent job and the one i currently have where i'm currently employed that's the one i will by default open right so in this case base esports solution in berlin that's where i'm making this video right now uh and i lead the development there of applications that manage and visualize esport related data right again with react same thing i'm doing here this is my favorite stack this is what i'm the fastest at so i can definitely recommend uh using the same stack because it just works so wonderfully for building apps all right so uh when clicking on the marker open the pop-up link all right so you just add an event listener to the marker click and then you take that google info window you defined before closed it because that's the previous one set new content and then open it in this new marker basic okay so that was all the code for the career page very good and now we can move along to um the cooking page all right cooking page is fantastic and super difficult i think this is actually frontend wise this is definitely the most difficult page there is a lot of stuff is happening here on the front and actually back into the cooking is a very hard page and i think also the most broadly applicable to other people because anyone wants a list everyone wants a list right like any customer any business even your personal website i cannot even think of a single example where people don't want a list with special properties and sorting options maybe as well right and then i added the extra features of creating stuff too so it it gets real complicated real quick okay so that's why i split it into two parts i split it into a cooking part and then a single recipe i've put separately and it was a good thing too because this is 182 lines for just a single recipe just showing only this block uh so it's quite heavy and the reason of course is because i'm allowing editing on it right so this turns into an object with all kinds of extra inputs it's like a wizard and i'm trying to make it feel small i guess in an older style you would have a separate page for this or a pop-up but i wanted to keep everything super nice and tidy and together but of course the code is different like i'm not showing this range attribute uh when you're done when you saved right here it's just a simple div so i i had to reuse uh the styling but i could not reuse some of the code because there's new elements that need to be inserted so we'll get over there let's first start with cooking in general so you can see a bunch of react bootstrap stuff form a modal for the delete the buttons the spinner the tool tip the overlay that's just for this little one recipes you create are only visible to you there so that's the overlay trigger and the tool tip doing that very useful properties very nice it also has a great website by the react bootstrap react bootstrap this website here components very wonderful this is uh everything you might want is here right overlays buttons all the kind of buttons the styling and you can change all the styling you can change the defaults but this is a wonderful library to use and you can definitely see it at work in this page okay so then a recipe i import of course and then the rest of the stuff comes from my hooks you selector use dispatch so dispatch again is to send something to the store and selector is to get something from the store and what you send for the store is an action right so i get everything from my store and then here i have a type called recipe 2 but because i already have an object called recipe i now rename it inside here add to recipe type just to make sure there's no confusion between these two um and i can still call it recipe which which is what it is right this this object is definitely a recipe this type is also definitely a recipe so i just wanted to keep them the same and here we have a hook for using aws uh my connections to my own api to implement aws endpoints and use query the the good old known use query actually i'll change this sorting i like sorting things basically based on length i do that a lot kind of creates more visually appealing anyway um all right so api url is taken from either def or prod event depending on the node environment easy okay so uh cooking dispatch save on change all right well this starts pretty difficult right away okay so like i told you use ref false means that you have a save on change dot current right and you can see it here too say on change current and that one is not tracked by react it lives on its own you know again it's it's some reference and we're going to use it because in this case we want to make sure that react doesn't update when this changes that's kind of what we want we don't want to track it and of course we can still say that we use save on change for instance inside this use effect we say save on change if that changes then execute use effect but remember that's the save on change as a whole if that variable itself changes but save on change current which is the object inside of it is not being tracked so that's why this is what we wanted because now i can say okay i'm using save on change here so i need to put it inside here because you want to be able to reference it the correct version and i put it on false when it's done saving the recipes by the way by default it is false and here we already say if it's not true then return so meaning in the beginning this won't execute it's only in other places where we say save on change is true like i said here this enables to use effect hook that saves the recipe the hook will only trigger after the update recipes action has updated the store because you can see let's go back here if recipes change then this effect will execute so if this value has been put on true save on change true current and then the store gets updated recipes get updated then this function will execute and then it will not execute again so this is a great way of kind of layering your effects where first i wanted my store to be updated and then i wanted to save the recipes after and i want to do this for instance also when i delete when i delete a recipe first i want to delete it update my store and after the store is updated i want to save the new file so that i can save the new list that doesn't have the thing i deleted anymore okay so save recipes in this effect using a special technique with a ref very hard very i'm sad that this is the first thing i had to explain about this page but anyway we're diving into the deep end and honestly if you're following this video and you're still here then congrats to you because you know this is a barrage of words and i i i guess you should probably just you know use the kit uh repository itself uh to to get a little wiser and if you're watching this video well then uh you're in for the bonus material so to speak okay so we've got recipes and user user will be null if we're signed out so this is just interesting because when you're signed out let me sign out things change you can instead you can see here add your own recipe sign in you don't see a create button and of course your your your own recipes are not visible anymore right so i need to know whether we are used whether we are signed in or not to do that and then recipes here loading upload save recipes load recipes so this is a bunch of things we're doing with aws okay we loading is a boolean yes or no are we loading recipes right now and if we are you can see it here you can see it oh maybe i should sign in so you can see it here there see that little loader right real quick that's based on this loading upload which is for the image so like you saw here when i select an image it uploads and bomb perfect this is so ugly i'm going to delete it but that is the upload function doing that and then save recipes which again is just a simple request of the server well let me go over it in the hook okay use aws this is a beefy hook it has a lot to do there you go you got upload for images save recipes for saving the the total json file that i have and load recipes from aws s3 now loading is the simplest one because again i'm just using a fetch like always so i already explained how i do this and you can see the structure is very much the same i still keep it in a separate file i don't i don't abstract it any further because i want to keep control over every line that happens here in every hook i write i don't want to uni make this uniform because for instance here you see i don't have an abort controller right because i don't assume that load recipes would ever be spammed in this case i felt like a load controller was not necessary so i don't write it right so it's beautiful like that and you don't end up with globalized functions with a million options i don't like that i'd like to be a programmer that is in control of every line so i don't mind that the structure here looks a little the same as you seen before because again we're dispatching to another place we might want to show a different error message this request is definitely different i mean in this case because we're requesting to aws i added headers before with the github request you saw that i only did content type application json but now with these i had to add new headers to make sure there was no cache from s3 because s3 is aggressively trying to cache your stuff but i never want to get the cached version that would lead to a bug in my system people would think that their stuff is not saved and it would be very sad so we're definitely putting these extra headers here to make sure we don't get that and here you see that i use that react app aws bucket environment variable to dynamically select the bucket and then based on the user's email i get their index.json and that's where their recipes live right so that's the file that i've saved in save recipes so let's take a look at save recipes here you see i go to my normal my own api i don't go to aws directly because in my view saving a text file i can do through the server saving a big image file on the other hand that i don't want to do on my server i want to kind of directly upload it to aws but in this case saving recipes is just a very small amount of text basically so i'm just going to post that directly to my api and i also want to check the credentials i want to verify that this guy is signed into google right like so i add the credentials meaning i add the cookie and i can show you um so let's let's again create one let's go to my network tab we're just going to save it right away and then show the xhr here we see the request right save recipes now if i go to cookies you can see that i have signed in user signing user signature right so this is this is perfect this is what i wanted and this signature will update it's a rotating key set so once i sign out it's safe again and these two basically are set because i'm working localhost which is also where i have my work so don't mind these two these are the only ones i use and by doing credentials include i'm sending those to the api uh and then here you can see that i take the recipes but i filter them out i filter out the default ones i only want the ones where this user created them user email equals recipe creator and those are the ones that i save on aws okay and then i send that request and i'll show you later how to save that in the bucket now the most difficult of all is this one this is where first we ask the api hey i want to upload this image give me a pre-signed upload url so i can use that to upload the actual image so here you see we're not really sending the image we're just saying this is the file name of that image okay very straightforward and then it comes back here we go with a response and the response is an aws upload response which i've defined myself which is again this is what aws by default does for aws uh pre-signed urls you have an upload and a link this is from aws this is my own creation the link will be the link that it is when you've uploaded the image right so after you upload the image you can start using link and but in order to upload it you need to go to the upload url that's where you need to post this image to and there's also a bunch of fields that they come which you need to add as well so um by the way what did i change here oh the sorting no problem okay here go back um so let's have a look at how we do this right so let's go to the upload function inside of the cooking page upload file okay here income incomes a file so first i want to show you where i execute this function it's inside of recipe here we go so i pass this function through the cooking page to the recipe to each recipe that's being rendered gets a reference to this to this method here it is and then i say i'm inside of a form control for uploading the image which is this thing this choose file button is this form control which is just a basic input with type file it's just default browser behavior and then when it comes in there's a change event right html input and then i will map over the target files i will loop over them basically and for every file that's in there and in this case you can only select one but this is just how the api works so i have to loop over it it's always an array i'm going to upload each of those files okay in this case only one so and then the index that i sent here is not the index of of this array because it's only one like i told you that's how this thing is configured you can add the parameter multiple by the way and then it would allow multiple uploads but of course in our case we only want one image and the index is actually the index that i get here which is the index of this particular recipe because then later after i'm done uploading my script will will save the url for this new upload in the right recipe so that when i click here and i upload the and the image comes back it knows in when it when it's uploaded in what of these which of these three to put or these four to put the uh image right so that's why i need the index the file and the index and the file again isn't is a is a default i did not define this type this is a browser specific i mean a browser api file api so it's very i didn't do anything to this right this is default behavior from the browser and i'll show you how this works so upload file it says okay i got my file i got my index first i'm going to take the file name and ask to upload it then i'm going to have either an error or a response if i have an error or no response i'm done i'm just not even going to do anything i mean i already told you that if something went wrong then the error was popped up here so if an error returns later we don't care if if response is empty we don't care we just stop okay so over here we don't do anything with the error because it's already handled so we just stop now i'm going to create a new form very manually form data i'm going to add all the fields that aws asked me to put on the field to put on them right so very straightforward just loop over there and append all of these properties then i'm going to add my file add the image and then i'm going to send this request straight to aws without cross-origin resource sharing just send a post straight up with the body to the url and you also have to of course configure your your buckets to allow this right you need to you need to be able to allow pre-signed urls and stuff like that but once you have configured everything on aws side you can simply post this and it'll be working okay so now uh i showed you that trick that i that i talked about before that you say save on changes current is true then i'm going to update my store because if you try to if you try to immediately hear on this line uh say that you save the recipes right because you know you just say okay i updated my recipe and then here save them right but the problem is that this dispatch is not synchronous it doesn't mean that right here you can already access and the the store is updated you need to wait you need to wait for that update to happen so that's why i do that trick where i say save on change so wait and then that that i can already put on true and react bond won't react to the to the change and then i dispatch and as soon as change happens it gets saved okay oh there's a problem in my card oh see this is where it's very useful to be able to do control shift because this is pretty fire at work i just use a shortcut bomb it's solved very clean okay we're going back uh no more problems back to the terminal okay so we're in cooking we were discussing upload file which we've now done and again i need to show you the actual backend for this but i'll do that later first we're going to go down to delete recipe which is very simple we make a shallow copy of the recipes new list slides we remove which splice we remove from this array the index that you want to delete and then we say save on change true dispatch and then set the other ones on null and this is the index that that keeps track of what you're trying to delete and what you're trying to edit because in the beginning you first say okay i want to edit this now the edit index is put on in this case zero right because it's the first one and then we say delete now the lead index is also put on zero now when i click on the lead that's when this function executes so it needs to put both those values back on null to make sure to not show any open editors or open modal so to hide them again right turn off the recipe edit mode hide the delete recipe model and of course this has now been updated we've saved it we send the save recipes request again to the server and it's all good so that is the cooking page of course the recipe itself well this is a serious serious object i mean we we have all kinds of special situations the default cards are different from the special ones that you create yourself mostly because of this choose file and all these other editors so you see me checking a lot if the recipe creator equals their user email right that's another one of those things and by the way this question mark is super useful basically it says if this object is null you can still check for email because it'll already stop at user and just return i think it's undefined right so it won't crash without this um you know it used to be old school javascript you don't have that and then you know object is possibly null so you could get crash your code basically and nowadays you just put that question mark there and that's that's in case you know that user might be null but if it's there check the email and then compare it with creator and these two values need to be equal simple okay uh well is there anything special i want to show you well um for instance here i say if the creator is the email then we show the picture that they have and their name and else we just show and i hard code this my image and my name so this is hard coded basically and this is dynamically coming from your user account from google basically it's your google picture okay here you can see me do a formatting for the date we have a nice proof what can i show i mean here the difficulty may be fun form control type range right so that's that little this one it's very default this is just a basic browser one nothing special probably looks really ugly in internet explorer i haven't checked um okay and every time it changes i dispatch a new action and i want to show you these actions real quick because they're not that many actions we got set which is a general action i use to update the whole store whatever you want and the spread operators here are super nice it basically says hey copy everything from state all the properties that you currently have in the current state and but then overwrite all the properties that you find inside of this new payload right so if you want to update something um so let's see where we do set right set uh not in the api but in the client for instance set error update that property so you don't clear the whole story just update error only error twilio here set twilio you know so your your only setting only updates this property that you define and leaves the other ones at the same as they were that's what this set function does add message is used in the in the slack page where we just push a certain payload on top of the messages we already have set online same thing and add recipes here add recipe is for a new one for when you create and click on the create button we add one to the beginning of the array and we keep all these values empty but by default we already fill in the user creator which should always be there because the button is not visible when you're not signed in and also fill in the created by default and then update is also really wonderful because there i put the index inside of the inside of the payload and then this way i extract it again so i extract from the payload index and the rest of all the properties to combine together to be the recipe so this this spread operator here is very useful because it basically you know i i think it's called rest operator anyway it's it's index is pulled out the rest is kept together but without index that's what you're doing in this one line of code and then you just say okay grab me the recipes based on this index and update that one and again it's uh it's a it's a it's an update meaning that this payload is leaving the properties that you haven't defined to be what they were before and only upload the new ones so that's why inside of this thing when i say update recipe i only give an index and a difficulty so the difficulty is the only one that's being updated index is being used to search it and all the other properties will stay the same as they were and this happens every time this range indicator gets dragged so it happens now happens now and now that's how that works and i do the same thing for duration and same thing for the text that you write it's all the same okay well uh this was the cooking page i kind of went over everything oh maybe uh no no no one thing i definitely oh wait i need to go out of edit mode in order to make this thing work this thing is kind of interesting because um like i told you about the query url right like this thing and i do want to show you how i did that so let's go over that in the beginning we load the recipes i showed you that hook i showed you this specific function from that hook saving the recipes with that trick we did that we did uploading we did deleting and here comes a special yeah this is the last one the sword of recipes so again this is a case where i wanted to know what the value was before because in some cases while editing a recipe you want to um you want to keep returning uh the same memo that we had before you don't want to recalculate the sorting when somebody's in edit mode i wanted to disable it because then i also have to update the index and it's annoying so i just want to disable it you can't sort or filter while you're editing so i say if edit index is not zero then we're just going to return the previous value that i already saved right so sorted recipes current is from the previous one because we're trying to recalculate the new one and in this case i'm only updating uh changes that are made to this specific recipe i'm not changing anything else so very straightforward okay but in the case you're not editing anything then i do want to calculate the new sorting so i'm gonna look at uh at these properties and again these properties come from here right so i look at the query sort and if it's not there then by default it's created i look at the direction if it's not there by default is descending right so that's my sorting and i only also have a filter for only my recipes which is that little checkbox here right in this case there are none because i deleted them all but so i use those boom over here uh to filter so let's first show it here uh when i go when i go over these sorted recipes there's a little filter right here right before i um show the recipe and that says if we have only my recipes being false or the recipe creator equals my email then we show it so that basically if this is true then we only want my recipes that's how this filter works so it's a very tiny little one liner that creates that filter and then for the sorting let's go back to the sorting here you see the swords so i take the recipes i slice them to make like a shallow copy of the list and then i sort that list a b so left and right and we need to compare these two and then the sort function will will put it in the right order right so we turn the direction into a one or a minus one depending on whether it was ascending or descending right and then we depending on what we're sorting on we change the function that it returns right or the the value it returns so in the case of javascript comparisons this is a very funny one if you just too lower case and name and you compare those two values that's alphabetically sorted right so so you can kind of act like it's a number almost um and that operation works in this case and also um so this this this is true or false comes out here and uh depending on the direction we're gonna either return one or minus one um so we're changing this based on direction right this is one minus one this is one and minus one time minus one so it can be it can be both minus one or one depending on and you can switch that by changing direction anyway a little bit complicated but it's actually not because uh yeah you just need to uh yeah javascript does most of the work for you in one line basically difficulty is the best one easiest one because here you don't even have to do anything you just take the difficulty a minus the difficulty b times the direction and that's your that's your sorting number right so there's a difference between the two and the same here we take we parse the json with the date then we do value off which gives you the amount of milliseconds on this date since 1980 which is you know the unix timestamp kind of so that's how we uh we we minus those of each other and then again do times the directions or one or minus one to uh fix the sorting so that then you end up with a sorted list basically so we just do client-side sorting very simple if it was a server-side sorting which you would do on huge lists you would probably do it server-side but again then we're talking about huge huge lists where you need pagination if you don't need pagination you can show everything on one page it's fine to do front-end sorting and in this case how many recipes are people really going to have even if i show all the recipes made by everyone on this website ever in two years it'll still not be enough um in terms of performance i can still show it just front-end so yeah we were talking about big databases before you decide to put that in the back end and again then you need pagination coming from the api and you just make multiple requests so in our case it would still be easy you just have a hook to the api and you make some fetch requests and you're easy okay perfect so cooking is done let's take a look at messenger this is not too difficult to do this is a pretty small one let's have a look uh oh boom i really have to clean up lines of code here boom okay let's resave so it just says i left the page and joined it again because it refreshed in the background but okay loading and send comes from the use socket and then send is what i use here to send a new message on submit and you can type and set that new message so again i'm typing i'm setting a new message and then when i do enter um or when i click on the submit button so that's the trick by the way you need to put this form around the submit button and and the thing you're trying to automatically send and only then does this enter button work right so uh oh by the way because i'm not on the server right now you won't be able to see my message because i'm on localhost and slack is sending these messages not to my local server but to my lookdg server so i can't do this test here i'd have to do it here right hi here it does work but low close it does not while i was developing this i had another slack setting where you don't need to use a server and it uses a socket instead with them but again that's just for development so if you want to have it in a server you need to turn that off eventually and use the events api which i did okay so um very good we have a new message and while the message count is not the same as the amount of messages that i have uh we're showing this loader that you see here in this case i added a message to my here i'll show you we can go to slack and the message counts the messages is zero because the api did not give me any but my message count went up by one because i sent a message like you can see that happens here so there's a disconnect now between the amount that i should have and the amount that i actually read and in that case it shows a loading symbol so that's how i that's how i do that one okay so uh and here you can even see like a message count higher than the messages length then show a spinner else show a paper plane nice okay so um another thing that i do here is that i say whether i'm online or offline and i have a class here too so this is gray because i'm offline and when i'm online it's green and then it also says i'm currently online or i'm currently offline all right okay so um and that property again comes from the api so this i can discuss this feature and this page much better from the api side that's really the complex part this part is pretty simple just render some basic messages you can see here messages map over them put them all together easy okay uh and last william twilio also pretty basic um oh the meeting page meeting okay well it's basic but it's still some code we have a local audio local video which is the left side and then we have on the right side the remote video and remote audio and i render these at the bottom you can see them tick tick tick here you can see we have meeting video wrapper local and remote right and inside you have a video element and audio element okay now when i connect well let's talk about that later let's first look at this use effect so when the page loads we have a use effect hook and it says if there's a token we're done so this is only going to happen if there is no token yet okay and a token is something that the api gives me so maybe i can show you tick tick tick twilio here it is my twilio request and it comes back with a token so if the token already exists then we don't do anything but in the first case it won't exist so we continue then if i don't have a query room which is this here by default you don't have it you arrive at the page without it then we're gonna create one we're first gonna find one in your local storage which is uh here right here because i saved the room here in case you kind of leave the page and come back you go back to that same room so you don't lose the person you're talking to if you want to get back it wasn't like an accidental click right but if we can't find it there if we can't find it in your local storage then we're gonna set it so we say set query room is the query room or nano id so we execute a new nano id because all we need to know is that this room is unique it's not it has nothing to do with security as long as it's unique uh we're fine right and and unguessable right because you can't guess a nano id when it's randomly generated like this and then you can share this link with the person you want to talk to and that's it and the web data itself like the data from your video cam and will be sent directly between the two anyway so that should be secure like the webrtc protocol handles that part so there's no real sensitive information here and you'll be able to see whoever you're connected to as well so should be fine now save the current room id to local storage okay so yeah you saw me get it before but if it didn't exist and i created it and now if that is the case because the first time on the website or something or you left the room which also clears your local storage boom but if you come back then again this will be empty so you always need to set it every time this runs you're gonna generate your room code okay that's what this does and then it's gonna get the twilio token with the query room now this token will of course it will return a token and set it okay and when it sets it this will execute because this is like the opposite part of the equation this says okay whenever the query room changes or the token changes i want this thing to run again but in this case if there is no token we stop right because we only want to execute this uh here if there's no token then we stop because we want the token to be set okay so we went to the api we went back the token was returned now we can give it to our twilio video plugin so i say okay we're gonna have a room but for now it's null i'm gonna connect with this video and video is coming from twilio right so twilio gives us this whole thing it's basically a hands-free approach super super easy connect to the token connect with this token and by the way here is the room that we're gonna use okay the token also has this room inside of it so these two need to be the same okay so uh then we're gonna get a room um if meanwhile somebody left the room we're just gonna stop right if the token has been removed if anything happens here we're gonna stop but now put the token in the rooms in this scope because we want that because we need that room to be accessible because if this use effect stops if we're leaving the page then we want to disconnect wanna disconnect or remove the listener from the room okay so uh that's why i'm moving it from inside here to outside here by doing this little technique with room room having it there perfect okay so now the video connected uh at least our local one always connected so i connect those immediately the audio and video and then um you can see that i first get the audio and video tracks which is kind of a complicated setup but yeah that's how twilio writes that code and then but i just get it out somehow right after a lot of digging and a lot of dots we get there and then uh we get the audio and attach it to the audio and video we attach and then i remove the function cl i mean the the class name hide to kind of show the video right because by default it's hidden um okay and then we're gonna loop over the participants we're gonna connect to the participants but usually you'll find that this thing will be empty uh so participant length will be zero so this won't execute but if it is by the way it would work right if a participant is already in the room it would work it would connect but this will usually not go this is what you want you want to listen for when someone connects because that's usually the case you come to the page you copy the link you give it to someone else they join done right so that's why you want this second part so the only connect function as you can see super important and that's the end by the way so we just need to know how to do this on connect which is the most difficult function i guess that we have so let's open her up and have a look so we get a participant right we know that we have a participant and then we want us to know whether when their video track or the audio track is available for us to show so we say okay when there's a track subscribed let us know and then if the track kind is video we connect it to the video and if it's audio we connect it to the audio and then the same thing for the opposite side right so if it's unsubscribed they left they disconnected their internet went down they left the page something then we want to know okay which track detach it and in case of video we also want to add the hide class because um it will show the last frame of the that you received in your video chat in your video thing so we don't want to show that well just hide it but we know that the actual track has been disconnected right so uh so it's fine and same with audio we just disconnected and that's it that's the whole thing for the meeting for the messenger for cooking for career and the dashboard the only thing i guess that is left maybe that i can show you is the use google this is the one that i haven't talked about yet oh and use socket which of course is a web socket which is pretty hardcore let's go over use socket first it's pretty complicated um so again by default when we're we're not we're mounted true mounted means like we you know we exist uh we this has been loaded into the page uh and when it unloads it gets put on false here uh here when it unloads this effect right this effect that i talked to you about user effect when it unloads we put this on false the use socket instance no longer run on the component and then my my event listeners will no longer be working which is on purpose right i want to turn them off so that's why i check on mounted here which is a good effect now send a json message if the socket is open um so you can see always if the token if it's not open then return and if it's open then we send it so that's how we just send something over the socket very straightforward that's how you send a message and i always send the property like text i can actually show you this socket like how it actually works network ws api look messages and here you can see i arrived on the page online true text text and i'm not showing you this text here because this is the text that i'm getting in my slack but i didn't want to show it here right so i'm just filtering it out but now i you can see that i said text hi and i got back an object from from my api that also said text i but like you said like you're sending this but i'm not showing it immediately i'm just showing the loader only when the api gives it back to me from slack do i verify that this message has been sent right so in that case i i get this object back with the date and who it's who sent it and uh and the text so you can see this how sockets work very nice up down up down beautiful um okay so is there anything specific that i want to show no i mean this is uh this is just initializing a socket i mean i just you just do new web socket and give the socket url that's how you set up a socket in the front and it's really straightforward uh the only thing you might want to do of course is you want to add event listeners to the socket for when there's a closing or an error in this case i immediately just start up the socket again and i try to initialize it immediately as well to add more listeners again so if the server ever goes down or restarts or some internet connection disconnects and connects again you should immediately be connected again to the socket so that that's a feature i try to write okay very straightforward now last one use google use google's beautiful one um we go to the authenticate endpoint to ask whether we're signed in this by the way executes on app i put this here so when the app loads up we have a reference for the socket but the immediate use effect we do is authenticate so we always authenticate now when we come back from signing in with google i'll show you again you can see it real quick as the website loads look it look at the url bar boom see that signing code equals this right so that that is a piece that's this code and that code i sent to my authenticate function and if i give that code it'll use that code to talk to google to see who i am and else as a fallback it tries to find out who i am based on the cookie that i have and if i don't have any cookie then it knows i'm signed out right so that those are the three things that can happen you can sign in with a code you can sign in with a cookie or you cannot sign in at all those are your options um okay and the cookie again has to be matched with an object anyway we'll get there when we talk about the backend um let's go to the [Music] use google authenticate perfect post we again include the cookies of course right that's a part that else it won't work and we need to send the code but again this could be an empty string so the backend will check and if it's an empty string i'll check my cookies instead okay and that's it and then it just uh it tells me if i'm a user and it will return null if i'm not so no matter what the response is i will just dispatch it to my store and put it under user and then i can render this image in this text when i'm signed in because my api will give that data to me and sign out very straightforward even simpler right like we just uh the only thing i had to remember that i initially forgot is to remove your recipes from your local memory and change the recipes to the default recipes that are in the constants file so i removed the ones that were loaded from your aws account when you sign out and other than that this is always null so it puts the user null recipes back to basics and you're signed out but now the cookie is also cleared because we can't remove the cookie ourselves it's a http only cookie so the the web the web client can't really reach that cookie i can't even see whether i have a cookie or not because it's http only right so when i when i show you this this cookies variables where was it so this is a websocket so it won't show uh xhr authenticate cookies here you go this cookie i can't read from the front end because it's http only as you can see there http only check so i can't reach it it's not visible from within the page with javascript it's only visible to the browser and to the api okay um oh yeah and i clear this filter only show my recipes when you sign out as well and that's it okay so now we talked about the whole client i took a while might not have been the best introduction but you know i just went over everything real quick talk a bit about it and hopefully you find this useful let me know um but now we're going to go from client to server so we're not done damn you thought we were done but no we're not we're continuing so first api um we've got a bunch of we got a very few lines of code honestly this api is super clean in my view i think this is one of the best ways to write an api there's many more difficult ways but i think this is the clean way that you want for especially for smaller projects but i would honestly do it for bigger ones too so we have in the start we have nodemon which is a script that starts something and then restarts it if it crashes and also changes it whenever any code changes right and there's a configuration for that which i've set here so i say if any of the source files change inside of this api then you can restart and then uh what does starting mean well it means mpx ts node src so this is a bunch of stuff npx is a system program that comes with a node so you have npm node and npx and mpx is to execute certain programs that you have installed that you don't have globally installed so ts node is not globally installed it's only installed in the node modules inside of the api but by typing npx it'll find it inside the node modules folder and execute it so this is the same as node but it allows you to write typescript ts node is that's it and then i say go to the source folder of course which automatically means it'll find the index file so that's where we need to start okay so let's let's have a start at the index file so in the beginning it'll load the environment variables into a file into the the things inside of this file will be loaded into the process environment variables that's what this method does and i showed you before this example there's a lot of secrets and codes and things we need in order to make this api work so this is a very important file and this way it gets loaded in then we have an http handler and a websocket handler coming from root which we'll use a little bit down in this code i'll show you first where we use it server is starts with being null but can also be a server right easy and then depending on whether we have an https port defined so in my local uh on my own computer i don't have this defined i work on http so i just have this empty and in that case we go to this else statement it just creates a server directly on the http port and else it creates a redirect on the http here it creates a redirect to the https and it sets up the https server with certificates that you have to sit on your server inside of the ssl folder inside the looptg folder which by default is also ignored if you go to git ignore you can see ssl is ignored as a as a file so you can put it there without worrying about accidentally committing it or something because of course these are your private highly is need to stay highly secure certificate files um okay so um index okay very good uh and again priv key sort and chain this comes from i use i use certbot uh to to get my certificates because you can get an ssl certificate for free that way so it's basically amazing you just use search bot and you can get https on your on your server for free do it it's the best way people used to pay so much money for ssl certificates was ridiculous but now you just can do it for free it's ridiculous the world has changed um okay so as you can see the http handler is used no matter if we do it on https or http alright so that doesn't matter it's just a wrapper and http handler is most important and then the websocket server takes this takes the http server and wraps around it so that if somebody now connects with that with the websocket protocol ws instead of http then it'll go to this ws handler that's how that works and here you see that i imported from root so let's have a look at root routes one thing that's interesting is that the slack web socket is i connect the ws handler directly to the slack web socket so slack is the only thing in my api that uses the web socket so i just connect them directly i just say like take that handler start looking at it like like like like slack once right because just for messaging and the http handler that's my baby that's the big one that's where we do uh routing to all kinds of other files inside of this api and it starts off being very simple i told you that the client is being hosted by the server as well by the api but it's just being routed from luctg directly to the server so i check the host and if the host does not exist or the api domain cannot be found so it's not api.ltg it doesn't start with that the hostname of this request then we're just going to say oh then this must be a client file so just load it like a file right so i just say return file request response go ahead do your thing right so this file is loads a static file from inside the client build folder okay so we're going to create a new url and we're going to get uh we're gonna get the path name of that url and then join it up with my uh build folder in the client that is just hosted on the api on the c drive like very straightforward and then we see if we can access it and uh if it not if if it's a folder by the way if an error we're going to show index and also if it's a directory we're going to show index right so index.html is like the default thing to load when anything goes wrong and then but if we everything went right and we found the file then we're just going to read the file as binary and also send it if there was no error we're just going to send it directly like here we get the type from the meme media internet type module which figures out what content type you have to send in the header right so you can have image jpeg or application json or favicon whatever so that this is automatically figured out by giving the file name and meme will figure out what to send and then we write it as a binary and done okay so it's very straightforward this is like your tiniest most people will use something like express or something only because they basically want this which is so dumb because this is like this is 35 lines of code why would you why would you use an entire library hundreds and thousands lines of code for something that's so tiny right so just use something like this right you can download for free from my github easy okay back to root so if it's not a file now we know that we are dealing with an api request they want data from the api so we're always going to send back the headers application json because we're always going to respond with json like literally never are we not going to respond with json so access control allow origin this is great because we're running from the look.gg domain and we're connecting to the api.look gg domain even though it's the same server in the end i wanted to write this server as if it could be separate so that i can put the client anywhere i want and as long as it's allowed it's fine in this case the only thing that's allowed is what you have written down as the client domain inside your environment variables that's the only thing that's going to be allowed to make requests okay so uh and again the thing about i don't know if you know what pre-flight requests are but if you do a cross-origin request the first request will be options maybe i can show you this here you see plus preflight so the preflight request is an options request maybe uh can i click this i'm clicking it but it doesn't work does it show me the options now select preflight i'm selecting it well anyway so you see this method here and preflight means that there was an http request before this get request and it sends an options method and it doesn't want any content it just wants to get these headers to know whether it's even allowed to make a request right that's how it works so as soon as we know that it's an options we and we set the headers we are done we're just going to set 200 okay everything's fine and we're done okay so now we're dealing with a normal request not a preflight request anymore so this can be a get or post but even if it's get it won't have any data but we can still do this so it we will do it anyway because we're waiting for the request to end before we're going to respond right so in in the case of a post that will take a while first because it'll it'll send the data first but for a get this will instantly continue so we're getting the chunks of data we're adding it starts off being empty we add all the chunks and then we're done and here we have the raw data so we're gonna try to parse the data which should always be json as well and parse it into the body and if it fails then we say oh something went wrong my bad and then body will stay null which is also the case for gets it will stay null right and because then the body length will be zero and just be null it won't even try to parse anything so buddy should be null most of the time except at the post and if the json data was correct um and then we are gonna route uh to the uh one of the routes which i just manually wrote down one by one very simple and i import these from other other files and if none of these were found then we're just going to say 404 and we're done straightforward okay okay so let's go down this list from top to bottom boom close the others boom github there we go github is a wonderful one very straightforward so we have the data from github and we need to know what the github start here was in my case 2011 uh that's when i created my github account and we're gonna load all the data from github but we're not gonna do it all the time we're gonna do it year by year and we're only going to do it if this current day has not yet been fetched right so if nobody has requested yet for today how many requests how many contributions i made on github then we will load it and else it'll be in the cache on the server so this is my local cache right so let's start off here with the default request in this case we're gonna say here you see that i'm checking for the current day whether it's in the cache and if it's not then we're going to generate the data again we're going to fetch the data from github so first i'm going to calculate real quick how many years i need to fetch the data from right so 2000 2011 and take the year for this current year and then the difference between those and that's the length of the array plus one is the length of the array of the amount of years we want to get we also want to get this here as well by the way so that's why we're doing that plus one because we don't want to just get the difference we want to get this one too so then we have total length again i do fill with null because else the map doesn't work so you need to fill with null and then i can use this index and i i take that start here and i add the index to it again so then i end up with an array of years like uh you know 2011 2012 to the all the way till the current year that's that's how that array works and then we're gonna do a very special thing this is amazing this is where we we await promise all and then the entire array is turned into a list of functions so it was a list of years but now for each year we're going to create a new promise for load year which i did here and because it's an async function it'll always return a promise and promise all wants to get a list an array of promises and waits for all of them to be done and then gives them back to you with all the results in that array instead so it starts off as an array of promises and ends up with an array of values and then we can loop over those values and put them together and we put them together for the contributions we put them together for the total and then we have a new local cache that's been updated and after it's been updated we stringify this and the next person that requests this data this will be false because we will have the local cache of these contributions for today right so then it goes immediately to just this last two lines where it sends the cache so it's very efficient we don't spam github we only ask once per day okay so now load here is of course where we really go to github for that specific year the reason i'm doing it per year is because that's the maximum year and the maximum time period that github allows you to load the data from right so else i would have just loaded it in one request but they don't allow that they have it paginated per year that's the maximum you can get so i basically get the current year it's later to compare and to make sure i get it from and the two and i say it here too if we're loading data for this year then load until the current date time uh that's my my final date so i have my from and my two set and then i make the request and it's it's a very straightforward graphql request i post it i have my github access token in my environment variables that's how my authorization is done and here i have a graphql query where i say all right give me the give me my github username that's the one i want to check i want to check in the contributions collection from this state to that date give me the calendar give me total contributions weeks contribution days count and date so you can see that the structure is kind of complicated way more complicated than what i have i simply have if you look at my types and you're looking at contributions this is the body that github has really complicated data set right array and an array instead of multiple that's how graphql gives it but how i save it in the end is simply like having the data as a string an object and then the number of contributions i made that day next to it and this is just a big very big object right so i don't put it for per every week for every year like i don't separate anything like i just put them all together because the date of course is already unique it has the full uh it's not it's not just the date like it's not just the day it is the year dash month dash day that's the format of this date so you and that's also what they use by the way so it's kind of useless the way they they separate and structure it but i'm sure they have the reasons i mean graphql is for a reason so yeah i just have it's much more simple in my local cache these are my contributions and of course the total is just a number just a single number okay so that is my github response and again i can show you what that looks like i should probably refresh and go together here you can see this is what i have in my local cache i have the total and then the contributions which is a massive file and if you go over it quickly you see only a bunch of zeros but you have to go a bit slower uh actually it doesn't show everything oh no it doesn't okay well it's it's a very big list and here towards the end you see everyday multiple contributions all right so um that is my what's my calendar is based upon is this request back to root and going to twilio twilio oh what a tiny file this must be the smallest file ever but you see a lot of environment variables that's twilio right so we're getting twilio uh getting the dependency the module we're configuring a json web token access token video grand stuff we ask for a new video grant for the room that the client wants that it's sending in the body right and uh identity uh something interesting too identity is something that just again it just needs to be unique for a user and i actually save it localhost and it so that if they disconnect and reconnect the twilio service will throw out the correct person that just disconnected and connect the correct identity again so it's not very important actually but uh it just needs to be saved and needs to be unique so it's just a generated id that we send over https to the server okay so um we get a new token we get our account our api and our secret so we can definitely prove that we're allowed to do this and then we add a grant for the video there to it for that room and then make sure that also the token is aware of what identity we have and then we turn that token to a json web token and that's the token that's being used in the front end and that's it so again twilio implementation is very straightforward like with the twilio.ts on the backend and the meeting.tsx on the front end and the use twilio hook those three files can give you the the entire ability that kind of skype uses like you know it's a video sharing service so you get all of that and then you can change it change it how you want it add features so i i definitely really enjoy their service it's it's wonderful and webrtc is great as well because the webrtc means the data doesn't even go to their server it goes directly from your pc to their pc right so there's no ability to be hacked uh when you're using webrtc uh at least twilio can't hack you because they don't really have access to the data you're not sending them the video itself the stream itself so it's super secure and that's just how two works uh i mean that's how webrtc works and twilio also has options to automatically do it differently but then you have to configure it in your account uh and again you can you can see in the code very clearly that it's not doing that when you're when you're using these other kinds of uh rooms these web rtc rooms which they call uh go rooms nice okay so let's look at the sign-in and all the other google stuff right because they're in the beginning when you click that link you're being redirected so when i when i click on this link initially you can see in the left corner that i go to api dot loop dot gg forward slash sign in and that basically is then routed here sign in to the redirect so it asks it it comes in and we're going to calculate real quick the url that we need to send you to right and it's straightforward like it's it's just a bunch of easy stuff and the only thing is the client the domain the google client id that's part of the uh part of the query parameters that you want to send uh and then we're gonna redirect you to there simple so that's that's that the initial one is super basic redirect the user right and then the difficult or more difficult one is when they come back um they have that code in there you know so again i'll show you you have to be quick but you can look in the left top they have this code variable in top that's then being sent from the client to us again and so here it comes here's the code now if there is no code i told you we're going to check the cookies right we're going to try to see if you have cookies set and if we do then we're going to find your user based on that email address but if you don't have an email address you don't have the cookie then you're just going to be null right and if we can't find that user in our local cache then you're also going to be null so by default you're signed out but if you have a cookie and you were signed in before then we're going to find you again okay so now we're going to go to the interesting case the case where we have code from google that you gave me and so i need to verify with google if this is truly you and then who you are and most importantly what your email address is because i can never trust you to give me your email address right if you tell me hey this is my email address like no like you're a hacker and you're trying to be that guy but you're not but google can verify with that token if you really are who you say you are so that's the authentication part right so i'm gonna make a request for a token to google and i'm going to put that code in and i'm going to also tell google who i am and where i redirected you to right like where you redirected to after you came back and i'm going to ask for authorization code okay so uh if it fails then we're gonna sign you out done right we're gonna send back null and we're good but if it did not fail then we have these tokens here right now and then i can use that token to use those tokens to get your get your data your user info and this contains your email as well so that's what i want and then i have the id token to prove who i am identity token so i can say this is the access token this is the id token give me the information of who this guy is and it should work i should not get to know who you are if it failed then we're gonna sign you out if it succeeded then i now know who you are and then i'm gonna save you in the local cache based on your email i'm going to save you and have your name your picture your email address and a bunch of other data and then i'm going to set that cookie with your email so that next time you're refreshed you don't have to do that code thing again you can just immediately based on this sign cookie um i know you are okay and that's it so that's the whole google authentication flow and as you could see in the front end it's actually really basic right like we basically did nothing we we took a code and sent you away right i sent that code and we got the user back and uh and when you tried to sign in i just sent you to the server again the server redirected you correctly to um to another place in google and that's it so uh very simple and again this file is also only 117 lines i mean i've written i've written like style sheets that are like 100 times bigger than this like this is ridiculous how tiny amount of code can can do so much because people love to sign in with google i mean who the wants to get their own forgot password nonsense uh account system you just want to use a service provider like google because if something goes wrong with their password or something goes wrong with their account and they need to contact support then they're not going to contact you they're going to contact google i mean that's that perfect part of a service provider that they take these services and they uh they just they're they're better than than what we can possibly be as individual developers okay so sign out super basic i already showed you uh all right we went over this so removes the cookie sends back null done slack so slacker is very interesting but i think i want to talk about aws first and then we do slack at the end because it also has the slack web socket and the http endpoint so let's start with aws because aws is also such a beauty and we're really nearing the end now this has been a long long video um okay so here we have the recipe type as well uh so again i'll show you real quick the types that we all we have right recipes the google module for the user the slack module has the websocket messages and you've seen these types before on the front end i'm just repeating some of them in the back and only the ones i need of course uh slack event here uh this is interesting that this is really like the way slack works with threat uh ids and ids for messages stuff like that github i showed you already and that was it um okay so with the recipe first of all we want to get the configuration for aws to get access we get our secret our region our key everything and then we want to specifically use the s3 service this is really the only one we want to use in this file so we get it here then again for the cookie reading i want to know what your email address is i don't need to know your user right i don't need to access that i just need to know your email address because then based on that i will create a folder for you that only you can use to upload things so everything you upload always be inside your email address like a folder that's very important and you can see how that works here so we can see if you want to upload an image we're going to ask aws for a pre-signed url we're going to split the extension find out what file you're trying to upload that file should be an image jpeg right because if it's not then we're gonna send hey you should only upload jpeg images uh that's currently what i what i want right easy um then we're gonna generate a unique file name uh and that has the email in the start right so you can see that the file key is always email and start which comes from google so this helps me verify that i'm not you know you're not put you're not messing with other people's files when you're uploading stuff you're always doing it within your own little playground and here you see i have another nano id so i know that it's going to be unique you're not going to accidentally overwrite another file and then i put the same extension that you had as long as it's a jpeg image you can keep using the extension that you were having in your file name okay and here you can see i finally do the actual sdk call where i say okay for this bucket i want a publicly accessible file i want to upload a file it's going to be publicly accessible because you're going to read it without authentication directly from the server right so i assume that these files these recipe pictures that you're uploading even though i'm not going to show them to anyone else nobody else is going to load them theoretically if someone knows the url which again is a very difficult to guess url but if they know it then they can read it so that means that if you have access you can actually share the link of your uploaded image that you find inside of the web page so it's just easy and i don't need to do any authentication is possible by the way to do authentication but then i would have to send the images past my server again which i don't want to do i want to save bandwidth and directly load things from s3 all right so then i give the key and that's it and then i told you before i'll send back the link where you can download the image after it's uploaded and the upload specifics that you need to send that form right so that's how the pre-signed url works now this is where you want to save the json of the recipes that you want to save right your recipes only yours not the default ones and this is even easier in this case i don't even need to pre-sign anything i just say okay whatever you just sent me is going to be saved into the file i'm going to call that file email and then index.json straightforward and i'm going to always make it public and also so i'm not asking you to upload it i'm doing it myself here i say s3 put object because index.json files are so small that i don't mind doing it from the server big image files i do care but small text files i can do myself and then whether it's succeeded or not i say yes or no and it's done so that's how a save works and now the final of the final the final slack integration this is how slack is done okay so we have a bunch of sockets here and we use those sockets um to tell people whether i'm online or not and when i write good morning so let me show an example when i write good morning then my bolt will respond good morning luke and that's what this thing is doing here you can actually see it here good morning or good night luke and that will change my online status originally i wanted to get the actual online status from slack however i read that they deprecated that api that real-time messaging api that they used to have for that that their own slack client obviously uses right because it knows whether i'm green here or not that one is no longer available to developers outside of slack unfortunately so i had to do something else i had to do the good morning good night so every day i talk to my bolt in the morning and the evening it's a very normal thing i guess um and uh here we say also something the channel that i'm using this general channel has an id and i put that id in the environment variable so that that's the way i keep talking to the right channel right okay so let's go back up sockets wonderful now you know this gets real complicated because what i would need to do is in the beginning when somebody writes the the bot will write in the slack but then that that message uh we from that point onwards we want to continue talking in the threat like like we do here right so if i say for instance here i say hi hello we're talking inside of a threat and in the beginning there is none right so the bolt sends a message and then it needs us it needs to set the threat for the upcoming messages that are coming from the websocket and that's what this function is doing basically or what this what this cue is doing it's it's basically saying this message will be used um how can i explain this i mean i can show you the part because there's two parts that matter here in inside of this system there is the websocket that's talking to my web client and there's slack events and this is slack talking to me that is coming from the slack api that's coming from our guys from the website right so that's the difference and i need them to communicate in some cases so here we have a thread the websocket always talks and call in within this thread so it needs to after it sends that message it needs to wait until the event gets read from the http handler and then that handler needs to set this thread and the way i do that is by pushing the thread into the queue so i say if we don't have a thread yet then we're going to send a function into that queue that will be executed by by the slack api basically when it arrives and that will set my thread right and then i will i will in turn also save a function that allows that slack api to talk to my web client so that's how i'm doing that here i'm connecting them this way so that's how i'm connecting them so these two objects this one is a list that's just executed once and this is an object that can be used for reference those are then used to send websocket messages or events the other way okay so a little complicated maybe a bit too complicated but um yeah that's why i put all these comments here so you can calmly read them and figure out how it works and of course it should work out of the box if you put your environment variables right and if you configure the slack api you need to configure a web hook and you need to activate the events api and there's also this small thing in the beginning and i wrote that here this thing to set up the web hook slack will verify first whether you own the server so you need to be able to activate you need to just turn on this line and nothing else which will send back uh the challenge that they write and then and then event and then uh slack will be happy with your api and it'll green mark it and put it under your bot so your bot will then be associated with your domain so api.gg is associated to my loop to g bot because i have verified it with this challenge okay so that's how it works okay and when this event comes in i can immediately stop the response so i just say okay thank you so thank you slack done because now we don't need to respond to the hook right that's not a user it's just a bot who is talking to me so what's important is this body that they've sent this slack event that they sound and i'm going to look into it and see whether a bolt wrote it and then set the thread like i told you before we're going to get the text if there is no text then it's probably something else it's some other kind of event that i'm accidentally getting or i don't know what it is like if a message is deleted i get it as well but i don't care about any of that right i only want to get the new messages so that's why i delete this or i mean i returned this i don't care about this i log unexpected events that i don't expect because i only know these two right now i haven't seen any others yet but if there are others it will be logged and i can probably add it to this queue so it i mean to this list to this array so it can be ignored because we just don't care about those events so now we're dealing with an event i'm interested in we know that so if the user writes good morning or good night we're going to switch the indicator and tell all the web sockets whether i'm online or not so that's important but let's ignore that for now too right so the whole good morning good night thing for the presents but this is the case when the user is actually using the chat right so we're gonna get that response function that the web socket has set from the threads and we're going to do it based on you know either the thread of this message or the id of this message that if it's the first one so it's either going to be if it's like this message then it finds this matches to this message id to the thread yes and if it's the first message then it won't have one of these so it'll automatically use its own right so that way we always have we always have a function to respond to so this should never be false but okay in the case where i'm connecting with localhost for instance this is accidentally false because slack is sending messages to the wrong api and it's not actually this whole thing is not even executing in that case so there are edge cases so i'm just checking whether respond is there if it's not we're done and then whether when i can respond this will go to the websocket and now i'm really sending finally this select event that i received directly to the client that has originally sent it and again there can be multiple people writing to me at the same time still uh only the people that uh i write to in their thread will get that message not everyone will get every message right so it's grouped up based on design i use the thread system for that and the web socket uh interesting now it's from the other side right so uh push to web socket this is the web socket handler that was defined in root so here comes a new connection right opened up and in the beginning i'm going to send them immediately whether i'm online or not of course and then i'm going to keep checking the websocket connection in case it ever closes so if it's open or connecting then i'm fine but if it's closing or closed then i'm going to clear the interval delete the thread clean up everything clean up the web sockets clean everything up right so we keep checking all the time whether it's still open and if it's not if something happens we're going to close everything and clean everything up in terms of memory and stuff and also just security that we don't want to have anything lying around okay so and then when a message is received somebody wrote a message to me there's only ever text inside of it you can't send anything else to the api we're going to send that text to the channel right then straight up and where if we have a thread then we're going to immediately put it in the message so it arrives inside here and else we're going to send it without it we're going to send it directly but we're also going to set this thread queue to make sure that when that message later then is received we will we will set the threat because here we do it and this is called uh oh no how did i forget that word i know that google even had an entire library with the exact same name trolling everyone because it was such a programming programming paradigm to do it but what i'm trying to say is the the the scope we have here this this uh let thread is this one we want to we want to access this inside the other function but by giving a function to it scoping it that then internally does it uh here here we're we're we're basically giving the other uh part of our code access to this part but not real access it can only access this function and can only tell us the threat that's it and then basically we do it from inside here i can't believe i forgot that word for it oh well it doesn't matter okay um all right so we have the thread set uh very good and again here we do the same thing if it's no longer open and delete the thread uh delete the function that is used to write back to the client that's basically what i'm saying and then send the message if it's not if it is open um and then finally here is where we actually send the message so this is talking about web sockets communication again but this is talking about talk to slack where i send the messages like i'm using a default slack hook very simple to set up because you just have a post and you put the message in there and it's done like it's just nothing simpler than sending a message to slack in the end because it's just this simple fetch request and again we log it if something goes wrong and then i can look in the server if anything went wrong all right well that was a discussion conversation about all the code that is uh required to write this app i went over every line i'm going to keep working on this this has only been four days so far i look forward to it and i hope that this video can help you in getting started with your project and well good luck
Info
Channel: Luuk van Egeraat
Views: 5,288
Rating: 5 out of 5
Keywords: TypeScript, React, NodeJS
Id: Cis8e-mZBJo
Channel Id: undefined
Length: 145min 7sec (8707 seconds)
Published: Thu Mar 25 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.