Real-time Chat Using Next.js And Django - Part 7 - Next.js and Django Fullstack Airbnb Clone

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay so now we can set properties as favorites now I want to create a page that can show all of our all of our favorites in one place so I'm going to reuse the same components as we did on the my properties and landlord page as well but I want to customize it a little bit more so let's go to visual studio code and I just want to close everything here first and then I can find the front end air and then I can create a new folder here called my favorites so new folder my favorites and in there a new page called page. TSX then I Can Begin by importing the property list property list there and we can also import get user ID because I only want to allow uh authenticated users to reach this so import Port get user ID and then we can set up an asynchronous function so const my favorit page equals async fat error function like that and then in here we can begin by getting the user ID sorry get user ID equals get user ID and we can wait for this to finish okay so now that we have the user ID we can check if you are authenticated and to just if you are we don't have the user ID because this will return none if there are none next return now we can generate the simple HTML just for this so main set the class name to be Max W set the max width to be 1500 pixels M Max Auto to Center this and px6 so there some spaces on both sides and PB 12 so there have some padding on the bottom of this um maybe should p y not PB so we have above and below of course and then you need to be authenticated but if we have the user ID then we can say return then we show the real page so I can copy this here but here I only want the pb12 and then I create a div here for the title should probably just the same as we have here yeah we can just copy this actually you can just copy the rest here so we have it I don't have to type it again so my favorite but instead of posing in the landlord ID here I want to PO in favorit and set the value to be true so we get a warning here now because this doesn't exist anywhere but we're going to fix that very soon but I just need to say export default and POS in my favorites page so now this page is finished we just need to fix this um so if I now find a property list that is not this one of course first but I can open property list TSX and scroll up where we have the property list props here we can pass in favorites favorit question marks mark this as optional and this can either be bllen or it can be null because um if you don't provide it it will default be null or false but we can also provide fals if we wanted to do that then we put in favorites here so we can use it down in the script so we already have this here so we can just keep scrolling I want to change this ha a little bit so if it's not a landlord page then we can check okay else if it's a favorite page then the URL should be this instead question mark is favorite equals true and here I don't use the back text because I don't need to pass in any variables or anything like that so then I think I can set this save it go back there are no errors there are no errors so then that looks good looks good down here so then I just need to change the back end a little bit so if I open up api. Pi inside the property app and find where we are listing out um favorite this is a list of favorites so it's not that variable but we can get it down here in the filter and we can say is favor equals request. get. get and just PA in his favorites and we can default this to be empty and then just like we filter for the landlord ID we can say if is favorite then properties should be properties equals properties. filter and then we want to filter everyone where favorit uncore in user so and favorite that not defined forgot to add the question uh equal sign so what this does is that it checks that if this list of favorites which is one of these fields many to man field contains this user then it will be added here and we will see it in the front end so we can save now and the last thing we need to do for testing this is to find the menu so that we can add the button to this page up there so open up nav bar and find user nav I want it to together with properties and my reservations so I can copy one of these and just replace the title with my favorites and go to my favorites and say so if I go back here now and refresh click there my properties no my favorites now you can see this page or sorry this property which is one of my favorites great so that means that now I can set this to done and then that was it for that task before I continue I just want to say thanks to all of my patrons if you do want to support me you will find a link in the description below so now we can continue to make the conversations Dynamic so if I go I think I hardcoded this previously in books yes so here I have a list of conversations these are just hardcoded but we need a button for this page as well to the inbox so we can have that at the top of this inbox inbox inbox and save so now we have that there click and you can see three hardcoded conversations so I want to make this Dynamic which means that we need to create a database table and an app for this in the back end so then we can start by going to the command line and we can stop this Docker running here so it consist of a few different things first you need to create the app so um to go into the jangle back end and see if I can use one of these commands start app chat no this is not running so so I can't start it so I need to start it here again I stopped it with the command line try one more time LS and now I have the chat up there perfect so um if I then go back to visual studio code and open up settings.py we need to append chat to this list here can add it at the bottom here together with property and user account like that you can save and I just want to close everything and if I find it at the bottom here chat we can open up models. p and begin by creating the database models so we need to import uu ID here import uu ID and import models but you can also import user that we have created previously from user account. models import user because you need to connect both the conversations but also the conversation messages to a user so let's begin by class conversation and pass in models. model I want one field for the ID I can just copy this for from here so I don't have to write this along here paste uh I want one for users so users equals models do uh many to many field so we can add both the host or the landlord and also the people who want to rent so in here we put in user and set the related name to be conversations which makes it easy to get all of the conversations for all of the users I want to know when this was great so cre equals small. dat time field and set this to be Auto now add equals true and I want to know when this was modified so each time a message is sent I want to update this field so modified at and this can be Auto now is true so this will only trigger when we add this field but this will trigger every time we save a conversation and then this is then the conversation and the conversation can have multiple messages yes so class conversation message did I write this correctly models do model and here I also want the ID field and I want a link or a forign key up to the conversation models do forign key in conversation set the related name name to be messages and onore delete models. Cascade so if you delete the conversation all of the messages from this conversation will also be deleted need a body here which can be just a simple text field so we don't have any maximum length uh sent to so we know who is the receiver is it landlord or the is it the tenant so this can also be a forine key so models. forine key to the user model and we set the related name here to be received messages so that you can easily get all of the messages you have received on delete that we just do the same thing as here and then we want to know uh who created it or who sent it but I like to use created by every time that I want to refer to this and this is also very similar to this we just need to change the related name sent messages then I can copy the created it so that I know when this message was sent I don't need a modified because you're don't going to change a message you have sent so then I can save this go back to the terminal and hopefully update the database so I think that if I now just run Docker compose up that did not help now because this was running so let me stop it turn it was stopped there if I run it now again you can see here check if the database is open running and then it found that the migration for the chat created to model and performed everything and the reason why this is working is because that we have this entry point that makees sure that these two are run every time we run uh Docker compose up um we can also just register both of these in the admin interface in case we need them there so from do models import conversation and conversation message admin. site. register conversation and admin site. register conversation message so if I save now head to Chrome find here I can refresh and then I can see all all of the messages and all of the conversations great so now that we have the database models we need a way to get the data out of the database so we need some serializers so serializers p now we can begin by importing this from the rest framework so from rest framework import serializers we can import both of the models from Models import conversation and conversation message and uh since we're going to show a conversation in the front and like this we need to get the name of the user and not just ID so we need the user d detail serializer from user account. serializers import user detail serializer and then we can set up the serializer for the list which is this one so close Ser no conversation list serializer and pass in serializer do model serializer um here we can say users so we just refer to this field and said that we're going to use this serializer up here and in here we can just say money equals true and read only equals true as well um we use this in case we're going to use this to actually create a conversation we are not going to do that but if we were if we have this we want to create a new user and then we say class mattera and pass in model equals conversation and which fields we want and here we want the ID we want the users field and when this was modified so modified at save so then we have the serializer and we have the models next we need the API field because uh we need to actually get the conversations and similar so I want to have this in a file called api. py here as well so we can begin by importing a few things from Jango HTTP import Json response and the API decorator from rest framework. decorators import API View and we can import the conversation model from Models import conversation and from do serializers import conversation list serializer then we can create the view for this API view this is going to just be a get because I only want to get this here uh def conversation conversations list and pass in what do you expecting okay um request and a colon there then we need to use this serializer here and also get all of the conversations for the logged in user so serializer equals conversation list serial pass in request. user. conversations. all we could assign a variable to this but we can also just put it right in here many equals three because this will be a list of conversations then we return the data by saying return Jason response pass in serializer do data so now we have the view for this as well next step then is to create the URLs file so to keep this as clean as possible we want the URLs file like that here as well so URLs p and from Jango do URLs import PA from do import API so we just import the whole file now we can set up the URL patterns equals part and when this is empty we want to use API do uh conver conversations list and we can set the name not necessary but we can set it to API conversations list and save so last thing now is to just find the Jango BMB backend folder with the main URLs file and create an instance here as well so chat and say chat. URLs which will point to this one okay so now I think everything in the back end should be ready to be used so let's head to the front end I can just close these files it's a little bit easier to keep track so then we can close the back end for now find app and locate the page inbox page. TSX so right now everything here is hardcoded so so we need to fix that at the top here we can import the API service we have created and we need to import a few things from react as well so import uh react comma and in here use State and also use effect because you need to do a few things when this is loaded and this should be imported from react um then up here I want to do the same thing with the user ID that we did on the my favorites page so um page. TSX in favorites we can copy this line and paste it at the top and we can copy these lines actually we can just copy everything down to there so we don't have to rewrite it again so we have it here so I can just copy this and paste it there um this needs to be converted to an asynchronous function like that okay so now we check if the user is authenticated and similar um I want to set up two um types that are going to be used down here because you want to need one type for the user and one type for the conversation just that we know which data that we actually have available for these two types of objects so it's top here we can export type user type equals and this should have ID which is a string it should have a name which is also a string and Avatar URL which is also a string and one type for the conversation conversation type and this needs ID which is a string and list of users and this uses this type up here so user type and add an empty array because it's going to be a list or an array of users then after this has been done we can do it down here now we can say const conversations equals a wait API service. getet and we want to get API slash um chat I think that's the correct URL and when we have these we can Loop through them and show them instead of these hardcoded conversations so down here we can say conversations map put them into a variable called conversation and this is a type of conversation type so now since we use typescript we know that this has to include these fields here if not it will crash so if it works then it works if it doesn't then we know that the where the error is at the curly Braes and say return and then in here we can say conversation and remove that one save so if I go back now and expected type error is not valid Jason um in order to allow non dat yes I need to set the safe parameter to be false on the API so let's go back here and say save equals false so then that restarted if I refresh then I get there but there are no conversations because we don't have any so let me just create an conversation in here between Stein Stein at Stein is the current user I'm in and I can talk with Stein at code with Stein save so if I now go back and refresh I get the conversation but the information here is hardcoded so that can be the next step to fix so here we need to pass in this object conversation converation like that equals like that and I also want to pass in the user ID since this is something we already got up here I'll get some warning Wars down here because these are not supposed to be there right now but that can also be fixed of course so I just need to find this conversation component here if I hold in my command button I'm not sure what this is on Windows I can just click it and the file will be opened so I need to rebuild this very much first I need to set this to be a client component so use client we need a router here because we need to be able to go into a conversation so import use router [Music] from they should come from next navigation not next router and we can import the conversation type that we have created down there so we don't have to recreate it import conversation type and we can import a custom button import custom button so we can use that to go into a conversation and then we need to specify which properties we can pass in here so then we say interface conversation props cly brace no equal sign and here we expect a conversation and this should be a type of conversation type and a user ID which should be a string like that I think I can set semicolons there and then this needs to be converted to a react. function component where we can pass in the conversation props and then in this here we can POS in the conversation and the user ID D and before we start doing this Dynamic we can initialize the router by saying const router equals use router and we can find out uh which of the users in the list of user is the other user so const other user equals conversation. users. find create a user variable B and we want to find where the user. ID not equals user ID because user ID which we have up here is your user ID um then in here um to check one thing I think we need to set a key here to be conversation do ID just so this field is unique like that um and then in here we can say other user question mark. name in case there is something weird going on I just need to do it like this and we [Music] can convert sorry use this here just create sorry move this separate lines and say on click and when you click this then I would create a function and I want to go to the use the router to router push pass in the back Tex and back slash inbox and then the conversation. ID and save so I think that should be it now so yes now you can see that I have Stein which is the person I'm talking to and if I click go to conversation then I'm sent to a conversation with this ID which hopefully is the same ID as we can see here great so then everything there is working so now I can set um this to done okay so this this page that we see here also needs to be dynamic but that will be a part of these tasks as you can see here so the next St now will actually be to start setting up the web socket so that we can have live chat um we're going to begin by installing um software we going to install channels defy and little bit like that when that is done we can set up basic consumers uh set up routing and before we do this conf configuration um yes I'm not 100% sure the what uh order all of this is going to be in so I'm just going to begin at the beginning by installing everything that we need so we can go to the terminal stop this and find the requirement txt okay we have already added this so that means that it's installed nice um so I can just set this to done perfect and if I find the settings. p I okay we still need to do some configurations yes but we have added no we have not added anything here okay so that's next step okay so up here somewhere in install apps we can add def n which is sort of a server thing is that channels needs to run inside the Chango then we can add a configuration here called channelcore layers so this is uh where we decide where the information from conversation should be stored for example in memory how you cach it or if you're going to use a red red disc and similar so the default way to do this is to do it like this the back I want to use in this tutorial is to just store it in the memory uh until we have stored it into database so we can say channels do layers do inmemory Channel um sorry Channel layer so that was it there um next actually need to add one more thing down here write down here we have something called wsgi application this is entry points for the web server into Jango for normal HTTP and https but we also need for asynchronous function so you need to set up asgi uncore application we can just copy this and replace it with asgi application so we are definitely going to get an error now if we try to run this but we just need to open up asgi and do some changes here so this um application thing here can be a little bit tricky to understand and you're not going to use it much when you have done this configuration it will work and you don't have to do it until you set up a new project anyways so just try to follow along do it a couple of times and hopefully you will get it after a while we can begin by importing a few things from Channel so so first we say from channels. we import o middleware stack from channels. routing we import protocol type router and URL router and from channels. security. websocket we import allow hosts origin validator and some this is something that we need to make POS uh to make sure the user is authenticated and similar because this is done a little bit different than other type of authentication that we have in the project this can just be like it is and this is just to set up um this sort of script there and make sure that this is the settings file that we are using then we get the application just like we do here and now we have sort of set up Chango and we can use things from the project and here is it from chat import routing and from chat do token or import token token or middleware so this is going to be created soon and this is going to be created soon then down here we need to just do some configurations to this variable here so application equals protocol type router this is then this type of router we're going to use here if it's HTTP then we just say get H application so we just reuse this up here and if it's a web socket then we say token or middleware because then we need to authenticate the user a little bit different PA in the URL router here and then say routing so routing. web soore URL patterns so I will take you through a few of these things very soon now and hopefully clear things up um so the first thing we can do is to create the routing file so inside this chat application we create a new file called routing. pi and this file is going to look very similar to the url's file so we can begin by importing Po from Jango URLs import import PA and from do import consumers we have not created this either but we're going to do that soon now we set up the web socket URL patterns this is the one we are referring to here this would be just like typical Ur URL patterns but we want just specify that this is a web socket set up a URL and Po and when the pot is ws/ string LST strr because we expecting a string here which should be called the room name and this should use the consumers. chat consumer. s asgi so next step then will be to set up this consumer um sorry not next step because I want to set set up this token or since we are just finishing up this asgi file um so I get that this is a little bit much information at once but hopefully I explain it so you understand token O.P this is a file we need to make it possible to actually use the authentication and token Authentication so first we can begin by importing a few things from D Jango we import the anonymous user which is a model from channels. DB we import database sync to async so that we can get things from the database while we are waiting for things to finish we import the base middleware because we're going to change the base middleware that comes from Jango I'm sorry channels and we import a token called or function called access token because we want to make a b to get the access token from the headers and the user account models user so that we can refer to a user so now we're going to use the database sync to I thinkc to get the user def get user which is a function where we can pass in a variable called token key we want to use a TR catchair just to sort of does crash so the server doesn't crash if there is something wrong token equals access token token key so now we get the access token based on the token key we pass in the user ID should come from token. payload uh and then user underscore ID so this should be passed in somewhere I will show you soon and then we say return user. object. getet where the primary key is user ID if this doesn't work for example if this user ID isn't set on this or this primary key doesn't exist then we need an accept here so accept exception s e and then just return Anonymous user so now I know that this will give us the authenticated user if it is there so now we need to set up the token of middleware so class token of middleware where we pass in base middleware because this is what we want to override here we can say def in it to override initial initialization method self and inner and here we just s inner equals inner and then we need one as synchr method async def call and when this is called and we want to pass in self scope receive and send and then there's a little bit of a long sentence query where we set up a dictionary we split the URL string that we get in the browser and we split it by the Amper sign to get the quer string Etc so we know what is in there and to get the token key with can token key equals query. getet since this is a dictionary token and then we can say scope user sorry I need to use it tles equals await get user pass in token key so now we get the user from this function and append it to the scope and a scope is sort of like a session so we just append the user object into that and then we call the parent function call and just pass in what we have here so now the scope and this token middleware should have the user that is authenticated so now the error there is gone everything looks okay here the router is almost okay we just need to set up a base chat consumer and when that's finished we can start try to connect from the front end okay so most of what we have done here is sort of configuration and similar so now we are actually going to create a file called consumers P which is where all of the magic will happen for the web socket so we can begin by importing Json which is something we're going to use here Json and we're going to import a few more things from asgi ref do sync import sync to a sync this is something we need to make it possible to store things in the database because we can't just directly do that in a in a socket from channels. generic. websocket import async web socket consumer and we can import the conversation message model from Models import conversation message this is needed to create a message then we create a new class called chat consumer which is the one we are referring to in here this is the file and this is the class name in here we can PA in a sync web socket consumer and then we need to create an as synchron function called connect and this is the one we are connecting to self um then we can say self. room name equals self. scope URL R kws room underscore next and scope is sort of the session as I said previously this is the URL route and then K works is everything that is passed into at the end here room name is this one so we just get the room name from the URL now self. room group name equals chat uncore percentage s to format this or we can say F and do it little bit better self. room name so we just build a different type of string that is the group name we're connecting to join room and then here we can say await to await for this to happen self. Channel layer so now we are talking to the thing in the settings. pi where we Define where things are stored temporarily group underscore add self. room group undor name self. channelcore name and the room name should be something unique because if not other users could also connect to this so we're going to use the ID of the property and the user or similar like that and when this is done we just await s. accept so now we should be connected to uh to the server you also need a disconnect function so sync def disconnect self um leave room oops leave room and then we just await self. Channel layer. group Discord so let me just jump out of this here we also can pass in these two variables and that's the disconnect functionality so um I think everything should be ready now we can try to run do compose up see if there are any errors no con no changes and now you can see that this ha has changed a little bit starting asgi /de version 4 version for is defy and this is still the same so if I go here now the back end is still working as it should and hopefully the front end is also working yes great so that means that now we have set up everything we need in the back end to connect to this at least so now we want to make it possible to connect from the front end by the way if you want to learn even more more Jango or view from me you should check out my website codit stein.com the site has many premium courses and a lot of awesome blog posts and for as little as $20 per month you will get access to all of my content and you'll be able to track your progress you can talk to me and similar so go to codit stein.com after the video and sign up so first we need to install one thing so just stop reac our next running here and say npm install react D use- web socket cut package.json just need to see that everything is installed I think I need more npm install socket.io and socket. i- client so these are all things that we need in order to talk to the back end not 100% sure about these I just see that I have them in my dependencies so let's just keep them there for now and then we can run this here again andm run Dev um if I refresh it should still just be like it is I want to open up the inspector because I want to look for error messages now that we're going to start working with the uh web sockets so I can close the asgi now under the routing and token or and my favorites and conversation and that one so I only have the consumers up because we're going to do some changes to that soon so if I scroll in here here and find the ID inside there and open up the conversation detail page here are a few or actually a lot of things that we need to do first we can open up the favorites page again just because um favorites because I want to have this check in the detail page here as well just to make sure that we are authenticated so make this a synchronous and then we just need to import this here as well like that so that did not exist was in a different folder just add do slash there as well um you want to need a few things from react so import react use State and use effect is uh from react and we're going to need API service API service and I want to set up a type for the message so export type message type equals this needs an ID which is a string it needs a name which is also a string it's need a body which is also a string and a conversation ID which is also a string and sent to which can also just be a string we don't need information about the user and created by should be a user type actually the scent to can also just be the user type which is then automatically imported there so then we have that and I need to convert this a little bit because we need to make a b possible to put in the parameters here so inside here we say params and then colon add the params again colon ID which is a string so now we get the ID from the URL in here as well um first we get the user ID and then below here we can get all of the conversation we can get the conversation that we are on so uh const conversation equals await API service. getet and we need use the back ticks SL API conversations slash API SL chat slash and then we just pass in pam. at the slash at endend and close with the back tick so now we should get the conversation from the back end which you're going to need to put into this conversation detail soon um this page doesn't exist yet so we can create that before we continue so we can begin by creating this serializer for this so inside the chat here we need to create one more serializer class the the conversation detail serializer oops pass in serializers do model serializers and here I also want to get the users so copy this and down here I want the same as this up here I want the same Fields so we can just save it like this open up the api. py inside the chat app and import it conversation detail serializer and we can set up the [Music] view so at API view they should also only accept the get uh request method the conversations detail pass in request and the primary key then we can get get the conversation by saying conversation equals request. user. conversations. get primary key equals primary key and this then makur that you can only get conversations that you are a part of and then we can set up the conver serializer for the conversation so conversation ser alyer serializer equals conversation detail serializer there rep pass in conversation and set many equals false because now we don't want a list of conversation only this specific one which is an object and we return this Chas response conversation PA in conversation serializer do data and just to make sure we can say save equals false to make sure that we get everything there and save so last thing for the back end now should hopefully to just append this to the URLs file so urls.py in the chat app part here we expect a uu ID with the name of primary key and they should use API do conversations detail and the name can be API conversations detail and save so now this should actually work so we can get the information about the conversation and then we can pass it into here so conversation equals conver CBR conversation get warning here now because this uh component here doesn't expect this so here we also need to do some changes we can begin by importing the conversation type import conversation type from the inbox page so now we know that we're going to have that here we can set up the props interface conversation detail props uh um then the curly bra here we expect to get in the conversation and this should be a conversation type we just need to convert this to a react. fc and pass in confir conversation detail properties and in here we also say the conversation and then um we can set up just like we did uh somewhere on the page for the inbox we had this other user functionality other user where did I use that other user conversation yes copy this function and go into the conversation detail because I want to have that here as well um the user ID here is undefined so we can post it in here since we have it here can just post it in and then we are suddenly expecting one more property up here user ID which should be a string Plus in user already and then the warning is gone nice now we can have one like this for my user const my user equals copy paste and here we want where the ID is the same as mine um okay so now we can start working on the actually connecting to the web socket So Below where we have this we can add these lines here so what happens here is that we create three new variables send Json message lost Json message and register so this is used to send messages this is to get messages and this is to handle when you are connected disconnected and similar and you can see here that I get a warning so we need to import this import use uh web socket from react use web socket and there we should also import the red State as well and then we connect to the back end which is this URL and we use WS instead of HTTP here because we are connecting to a web socket this is was at the beginning of the routing. P file and then this is the room name because it's the conversation ID here we need to pause in the token for the user so that we know in the back end if you are authenticated or not so we need to get that here as well token which is a string and we can pause it in here token comma and then we should get that somewhere here so we can just PA it in and this should be easy to get um at the top here we can just say import get access token this is a function we have created earlier and then con token equals await get access token so now we have it here in case we should need it somewhere else now we can just PA it in to the conversation detail so now we have it there and we can send that as well to the back end nice to know if we are connected or not we can use a use effect so I need to import this from react import use effect and this will uh launch lach or trigger every time this is changed or if you are connected if you're are disconnected and similar then this will show in the console so we can save now go to the browser and see what happens here um okay conversation to the user is undefined okay um maybe I did something wrong in this one I thought the user this was supposed to be in that one we have a list of users so why doesn't that work let's add a question mark here so this will only trigger if there is users on the conversation yes so let's pretend that it is working connection State changed to one so it went from zero to one and if I go to the terminal then you can see here hand tracking so it's starting to connect the room number is undefined so there's something weird but you have at least connected to the web sockets now but you have at least connected to the web sockets now nice but why is the conversation ID is undefined that's why the user doesn't exist either um string undefined yes this is might be undefined um so so let's say if use not user ID or if not token and then we go in there just to make sure that we actually have it before we go down there so I think the reason why is that this is actually both if I open up api. Pi you can see that we are posing in the conversation there so you need to say conversation dot conversation great so if I refresh now then if I go here now you can see that we're handshaking and we are connecting to the correct IDs there and that's why also the users and similar are working now great so now we can actually connect to the back end using web sockets and we are connected to this specific conversation so now I can set this to done and then I want to make it possible to send and receive messages so the first thing we can do is to change the consumer a little bit here we need a function for receiving messages but also for sending messages so let's just add a comment there receive message from web sockets and then we can begin with the function async def receive self text data and this contains all of the information we need so we can load this using J Jon data equal jason. loads POS in text Data then we need to get the conversation ID from here conversation underscore ID equals data data because this contains the object called data and in there we have the conversation ID copy and paste because you need to know who we sent this to sent to ID sent to ID we need to know the name name and name it's just easier to keep track this way and the body which is the message itself and when this is done we can save the message to the database but we have not come that far yet so we just want to send this out to the rest of the users so now we say await self. Channel layer do group send self. group room group name want to talk to this and the type of message we should send is chat message this could be for example um if you start typing and you want to show that to other users this could be a different type want to send the body and the name so it's just easy to show this in the list of messages so this sort of just receives things from the from the chat these will be used later that's why they are grade out and then we want to have one message for uh sending messages so this is then sending it out again to the group so await sorry sync def chat message this is this type here if you want to create more then this one self event then we get the body event body and the name event name and we can say await self do send and what we want to send is text Data equals json. dumps create an array and we want to send the body with information from the body the name with information from the name variable so that should be what we need to do in the back end there are no errors nice okay so now that everything is done in the back end we can continue to the front end so if I find a conversation detail we should have this send button um this should be connected to a function so just replace this with s message so this is done getting a warning we can add that here for now const send message equals this is definitely going to be an asynchronous function like that and const like that so then that warning should be and then this text field here need to be connected to a variable or a state so value can be sent new message and when we oops when we change this so on change then we want to pass this everything into an event and say set new message and POS in e. target. value okay so now we get two new warnings here because we don't have this so let's begin by importing use state it and then at the top here we can say const new message set new message alss use State and just default this to be an empty string so now we have a way to get track of the message there and then we just need to configure this to actually send the information to the socket so what I want to do in here is to call a function go send Jason message which oops is the one we imported there and this should have a few fields for event can be set to chat message you probably recognize this from the consumer here so we get this here and it's sent back and forth with this name so I want to send a chat message and this should have a data array with the body field new message which is the one we are writing down in the text field down there uh I want have the name which should be my user if this exists do name and sent to ID should be the other user question mark. ID and we need to bust in the conversation underscore idid and that should be conversation. ID so these four Fields here are the one that we are getting here um when the message is sent then we can say set new message to be an empty string so it's cleared and after a few milliseconds I want to scroll us down to the bottom of the div where the messages is so set Time Out Create a function in here just call scroll to bottom and this can be triggered after 50 milliseconds so I can just create this function before I do anything else scroll to bottom equals CR the function and this can say if messages div. current so you can see that if this reference is existing down here then we can call this by saying messages div do current do scroll top so we call the scroll functional in there equals messages div. current. scroll height so then we this automatically scroll to the bottom height like that okay so I have a few warnings here now because this doesn't exist and there is a little typo messages div so let's import use ref use ref from react so that we can actually refer to a message div and then we can say const messages div equals use ref POS in null as a default value and then down here it should be on not that yes this element which has all of the messages then we can say ref equals messages div so this will then scroll to the bottom each time we send a new message so let's go here now and refresh see what happens refresh the back end and disconnect actually not sure if this so typo and um property scroll that does not exist on type never um so let's add this question mark there [Music] no want to add the console log here send message so it's easier to see that when we have clicked this but first I need to find out why yes now I am connected so let me try to send a message nothing happens there nothing happens here actually just this sent and this is emptied so I think that we can send the messages now now we just need to receive the messages and print them out in this list um so to do that we need to add an array to keep track of all of the real time messages so here where we have this you can say const real time messages set real time messages and this is a use State because we need to keep track of them in there and we want to set this to be a type of message a list of message actually and empty this by default now we get a warning here because we have imported this yet so we can do that import message message type actually sorry message type which is the one we created for the conversation list um now that we have this we can Loop through each of these messages and print them out in here so below here we can say real time messages map create a message page there like that and we can get the index as well for the key create the parent assist and we can just a div key pass in the index key there and then we can say close name and um here we sometimes need this class and sometimes we need that CLA so we need to do this a little bit different so we need a cur bra and the back takes so we can set the height no sorry the width to always be 80% because that's on all of them the padding and the rounded Xcel is also on all of them but if the message. name is the other is your own message then we need to do one thing and vice versa so if message. name is equals my user. name then we set margin left to be 20% and we can also set the background to be blue so that's your bubbles if that's not your name then we can set the background to just be BG gray 200 okay so we can close that Dev and we can close that div so all of the war warnings are gone then we can print the name of this user so message. name and then below here the message. body save so if I go back now try to refresh try to send a message nothing still happens because we have not appended the messages that we get from the server to this list so that's the last thing we need to do for before we can actually test that this is working now so to receive the messages let me just remove these too so I don't have any hardcoded messages I want to use one more use effect and this should have the dependency for this last Json message and every time that we we receive a message I also want to scroll to the bottom so that we are always on the bottom of the convers ation um here I want to check uh the message type and a few other things so I have this long if statement there so first we check that this actually has value then we check that this is a type of object we see that name is in this and we see that body is in the information that this has okay so that means that we can proceed and create an object of this so then use this here oops message type so I want to create a new message and say that this should be a type of uh message type and here we are expecting an ID which can just be empty for this case we set the name that comes from the server the body from the server and the conversation ID which you already have and then this can be appended to the list of real time messages by saying set real time messages parentheses and one extra parenthesis where we pass in real time messages Arrow function and to an array and here we want to unpack all of the previously real time messages and we want to append the new message at the end there um conversation ID string so don't open this I missed the sent to and the created by so sent two that uh I think should just be the other user and uh the other one was created by should be my user so get new warning here now user type maybe I need to import this import user type there let's see if I can use that then user type no s user type like that yes and S user type so then I can save now go back and refresh check here I am connected try to send a message and then the message appeared wonderful uh the name is missing I see that but it is at least real time now message. name why is it missing um consumer it gets the name pass in the name it has the name there it has the name there um and when we send the message my user. name it might be because my user doesn't have a name let me just set the default name for now John and just comment out this for now so you can just see that that is actually the problem yes it's just because my user doesn't have a name um You probably have that I just probably created my user in a dumb way or something like that but now we can send and receive messages if I had two screens now you would see that this was working in real time next up then is to store and load the messages so the messages that we get now is not stored in the database so I want to do that so I just need to create a new function here that needs to be called up here so this needs to use this uh sync to async functionality and we can call this def save message in here I want to pass in s since this is a clause I want to get the conversation uncore ID I want to get the body and the sent to and sent to ID and this should say user equals self. scope user so this is what we did previously when we authenticated user with the uh with the middleware similar and then we can say conversation message doob dot create PA in convert conversation ID equals conversation ID that we get from up here the body can be set to body Des sent to ID can be sent to sent to ID and created by can be sent to user which we are authenticated as so after this is now then sent to the group then we can down here say await um save message this actually need to be self. save message since this is a clause now we can PA in the conversation ID we need to do this in the same order we need to put in the body and the sent to ID so um there we are now redirected there let me try to refresh and send the message and see if it will be stored there are no errors at least that's great conversation message yes it was stored nice so last step then is to go to the to-do list again is to load the messages and print them out at the beginning of a conversation so if I now go to the serializers in the chat we need the serializers for the messages so close conversation message serializer PA in serializer do model serializer and then in here we need to use the user serializer twice so copy one of these replace this with sent to Manny should definitely beit false here because we only sent to one paste it again as I create by many should also be set defaults again set up the class meta for the configuration model should be conversation message whoops conversation message and the fields we want here is the ID we want the body we want the sent to and who created this so created by so now close that and open up the API and do some changes we already have this so we just need to import conversation message and conversation message serializer and then down here we can say [Music] conver messages serializer equals conversation message serializer we will passing conversation. messages all so we just get all of the messages that are stored for this conversation set many to be true then we can PA it in down here just say messages messages serializer do data and save so the back end should now be ready now we just need to store them into a state here so maybe I don't need a state after all I think I can just reach them through the conversation so above here I can try to say conversation do messages no this doesn't have that of course no um sorry sorry sorry I need to open up the conversation page I want to do there so in inbox ID page. TS X so here we have the message type and here I want to set up a list uh with the variables for the messages and then in here um the messages should be somewhere here maybe I can just copy and paste this and say old messages and set old messages we use the message type here as well scroll down then we can have one more use effect and they should only be uh run one time since it's only one to be loaded when we load so the dependency can be empty here and then I might be able to just say set old messages to be conversation do messages property does not exist on type conversation type um okay let me try to do this a little bit different just remove this and remove this open up the page. TSX in the inbox here for the conversation detail page messages equals conversation. messages I just get the warning because messages isn't expected up here but we can change this a little bit that might be the easiest way to do this messages message which is an array of message type and then I think I can just Loop through the messages directly so I can make it copy of this and messages cannot find messages did you mean sorry forgot to pause it in down here messages so warning is gone go back and refresh and then I have that there great um the name does not exist um it's probably because there isn't a name on that one um so instead of saying just message. name we can say message do created by not name that did not change anything um again I think it's because my user doesn't have a name and I don't have the user there sorry let me open up admin not p in the user account and just fix this once for all from dot models import user admin site. register user go back and refresh now I have the user here I find Stein Stein and I can set the name what should that be code just so separate it from my other names please correct Avatar go back and refresh and now you can see that I get a name there if I to send a message it will be sent under there great but the message isn't blue that's not good created by so if I save now refresh still not blue my user. name what can this be why isn't that coder so they are the same so now it's blue and I use double quotes okay is this working no message. name message username it's most likely because the name there is John now so now I can remove this one refresh so now it's working so the blue is there if there was another user talking to me the gray bubbles would be on the left side great so now we can send messages everything is stored in the database and similar so I can set this to done okay so now I want to make it possible to start a conversation with the landlord so I can begin with the the back end for this as well so the consumers should be ready now this should actually go in the API itself so if I scroll down and find chat API then we can create a new view at the bottom here API View and I still only want to use the get request method because I want to just get a conversation ID um def conversations start a request user ID and this will be the user ID for the landlord so first I want to check that if there is a conversation between me and him conversations equals conversation doob do filter where users in equals user ID um so first I get all of the conversation for that specific user and I want to check if I'm in that list as well so filter um users in so double underscore in equals request. user. ID so now I filter conversations that I'm in and that the landlord is in then I can if conversations.com is greater than zero then I know that there is a conversation I can just say return Jason response success sorry C success set to be true Double C sorry and I want to get the conversation ID so conversation _ ID should be conversation do ID um I need to get the first in that list um so I should say conversation equals conversations. first there are not more than one anyways but still this is how I want it and then um if there isn't a conversation we need to create it so else then I say user equals user. object. getet we primary key is user ID so I just get this user from the database I need a model for that from user account do models import user capital u and then I can say conversation equals conversation. object.create you just create an empty object for that conversation. users. add request. user conversation. users. add request dot sorry not requested user but now add the other user and then I can return here as well just like I do there so then I know that there is a conversation at all times so I just need to set up the URLs file for this so between this we can say po start sorry Start sluu ID and here expect a u ID called user ID and we want to use api. Converse um what did you call it conversations start name can be API undor conversations start and save so that's everything we need to do in the back end to create a new conversation so now I want to make it possible to go in to one of these properties not my own of course let's go to the first property where Stein is your host and then I want to make it possible to click this button to be sent to our conversation or to create a new conversation so first first we can go back here and find the landlord detail page so that should be in landlord's ID page. TSX on this contact button I want to pass in the user ID that is um my own ID user ID and I want to pass in the landlord ID that I going to talk to land lord ID here we can PA in the params ID which is the one we are visiting so I get some errors here because the contact button component isn't expecting this contact button so this needs to be rebuilt a little bit in order to make this work so convert this to a client component um and if we are not logged in I want to log in the user so let's import the use login model so we can prompt that up um import the use router from next navigation it's important that it this next navigation and I want to import the API service so we can check if there are a conversation or not with the function we just created so now we can set up the properties interface contact button props here we we are expecting the user ID which can be a string or null and we are expecting the land lord ID which is also a string but this cannot be null and then we just need to convert this to a react react. functional component and pass in the properties and pass this in here as well so we can use them user ID and landlord ID now we can initialize the login model equals use login model and we can initialize the router con router equals use router and when we click this div down here I want to call a function so down here we can say on click equals and we said just start conversation and I get the warning now because we haven't created it that will be the last step here so const start conversation this should be an asynchronous function like that in here we can check if we have the user ID if we don't have the user ID now we can just say login model do open and we will be showing the login screen um if you have the user ID we can say const conversation to get the conversation from the server await API service. getet use the backt here um SL API SL chat SL start slash uh pass in the landlord ID add the slash at end and close the back T what's wrong there I just used front tck or something weird okay and when to get this back then we can say if uh conversation. conversation ID we should get that anyways but just nice to make sure then we can say router. push and then we want to go to use back text again slash inbox slash pass in the conversation do conversation ID and we should have a conversation so if I click this now I'm sent to this because there is already a conversation with this user and I can talk there if I refresh the messages is there nice so that means that now we should be able to start conversations as well maybe I can select a different owner for this property in Angola we set that to admin at admin refresh that was not that one it's not this one so then it's the last one of course oops went a little bit too quick um okay it was This one belongs to admin okay let's set the name to admin so I can separate them a little bit he also needs an avatar save and save so if I refresh now then you can see admin is your host let me try to start a conversation go new conversation with him refresh the message is there and if I go to my inbox I do now have two conversations there perfect so now we actually just have one more very big task before we can deploy this project nice and that was it for this time if you have any questions about today's code feel free to leave a comment below and I'll answer as soon as I can see you in the next video
Info
Channel: Code With Stein
Views: 1,148
Rating: undefined out of 5
Keywords: code with stein, django, learn django, django tutorial, nextjs, tailwind, react, realtime chat
Id: KN8a4jNB7oQ
Channel Id: undefined
Length: 100min 41sec (6041 seconds)
Published: Mon Mar 25 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.