Fullstack React, GraphQL, Hasura, Nhost - Reddit Clone

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is rather amazing.

Well done.

👍︎︎ 4 👤︎︎ u/VIqbang 📅︎︎ Oct 20 2020 🗫︎ replies
Captions
hi i'm yuwan co-founder of nhost yesterday i saw ben's full stack react graphql typescript tutorial where he builds a reddit clone in 14 hours in this video he does everything from scratch the backend the front end the deployment so that we can see all the steps involved when building a full stack application the the video is great i really enjoyed it videos like this creates a lot of value for developers like you and me ben's video actually inspired me to do this video as a com as an comparison video to show you an alternative way how to build the same reddit club so i'll show you on an alternative way how you can build a reddit clone as the saying goes there's many ways to skin a cat that is to say there's many ways to achieve the same goal ben showed you one way that worked i will show you another way that also works now you will see the uncut version of me building this reddit clone that means that you get to see all my mistakes and how i fix them in real time i will be using enhos together with hasura react apollo and tailwind i will start by creating an enhanced project set up the next js and make sure registration and login works after that i'll add a tailwind css to make things as pretty as i can after that we'll be adding apollo to be able to create list update and delete posts and at last we'll do some clever uh stuff around up and down voting uh that uses some of the amazing aggregation capabilities together with hasura i think you will enjoy this video let's go so the first thing i was thinking of doing is uh create a threaded board so we can keep track of what we're uh what we're doing and what we're gonna do and what we have done so let's just start by filling up the backlog here so we wanna do authentication right or maybe start with create n-host project after that we want to set up js we want to be able to register a user login user after that we need to uh create a post and yeah let's we're mixing the backlog stories here a little bit between user stories and you know what we what we want to do but create post uh edit post upvote uh all right so that's a summary of what we're what we're gonna do here so let's start by creating another project so at nhos.io you can sign up i've already signed up with my github account so i'm just going to create a new product project called reddit clone and yeah a quick story about then host dennis is a back end as a service so what's happening here we are creating the product setting up the database fixing configuration setting up password authentication and storage so you can see here let's see let's reload this one postgres hazard graphql authentication storage up and running so we have dire we have like our own database our own instance of faster authentication so we can add users um register users all that i'm gonna delete this one because we we're gonna do this in the in the reddit clone so that's nice and what we're going to use mainly here is these two urls so we're going to get back to those all right that's done um so next next let's set up next as4 for our project here so i think what i'm going to start by doing is do creating a new repository on github so reddit clone we can have it public add a readme file yeah great repository let's clone this one get cloned and now do npx next create next app yep okay let's remove this one okay the next js app is installed here and let's just make sure it works so let's do yarn dev i'm going to split my screen here and increase this a little bit and do code let's make this big and increase the size here a little bit so we can see what's going on and let's see now localhost 3000 pom-pom-pom yup next yes it's up and running perfect and we like okay so that was the setup is done actually now we want to register a user and that's going to require a little bit more work so far we've been pretty quick but uh now we're gonna register the user here so i'm gonna go over to um github.com and host and host jssdk that we're going to use actually we're going to use let's see react and host so react and host helps us with the two things one is authentication and one is apollo so we will just wrap our whole app around these two providers authentication provider apollo provider so that we can easily login users and request data back and forth so let's do that um need this one here i'm just gonna install a bunch of things now so react and how to do yarn at let's install this and uh let's see now pages app all right i'm actually gonna rename no i'm not gonna rename this one actually but i'm going to do this i'm going to clean up this a little bit we don't need the versa logo we don't need a fabric on we will not use these css styles we're going to install tailwind in a second here so i'm gonna remove that one we have nothing in the public directory now we have nothing in styles we have an index this is the default one yep i'm gonna remove the css and uh for now just return let's just return hope and we're not gonna use this one either very clean setup here let's see what's going on okay so just home just home that's good let's see now so we we've installed react and host and all this and i think also we need to install nsjs sdk yeah we do so let's do that yarn add lcs sdk and also what i like to do on new nextgs projects is to configure js config i think it's called to make imports a little bit easier so js config js config.json yeah so new file yes config.json and let's just do it like that and um a last thing that i also like to do is to have everything in a src folder so we're going to move pages to src here oops was that maybe that was a file new folder src move pages to src cool and actually create a com utils and in utils we're going to create a new file called enhost.js and this is where we're going to initiate initiate and host so it's very simple import nlc js sdk and provide the backend url for our project that is this one here and then we initially initially initialize the application and initialize authentication and storage and export authentication storage so that we can use them across our app i'm going to save that one next thing i want to do is continue to add the two providers so you can see here we're gonna actually this is create racked up let's see if it's different on next.js should be the same so we can still use this one i think let's see so in underscore app.js let's import everything we need here and return actually we can copy this and uh we're gonna this is gonna be instead of our app and uh what do we have here we need to have a return right okay so now we're using the auth provider the apollo provider we are passing in the authentication object to both of these two providers and uh we're passing passing a graphql endpoint as well and this one is not it's just a placeholder so so let's copy in the right one here that would be nice to just click and copy automatically here but okay all right so we have our two urls we have the back-end url for the nsjs sdk we have the graphql url for the end of the polar provider now let's see uh we have jss config yeah this one should be actually like like so so dot src so that we can why do we do that yeah that's because now we can import easily from src so we don't need to specify an exact path we can just do utils utils is a child on src on the src folder so this should work let's see what's going what's happening 404 hmm we probably need to restart everything here since we moved the pages folder to the src folder ooh improvements oh yeah i am i know i know what this is we actually need to do another thing here we need to do src ssr maybelline let's put it false see what happens let's see i think we have an issue about this set this ssr yeah exactly successor we should set this automatically instead of doing this let's see if next gs is happy now it is home perfect all right all right so we so we have done a lot of setup here uh we have set up the ns auth provider the apollo provider we have configured the back end here with an ost sdk but we still haven't to register a user right so let's try to focus on that so for that i'm going to create a new file here called register or maybe before uh let's do this register dot csx i'm gonna use jsx here for for the for the file names so react comp register and export default that's nice register so let's just go to register now and see what happens yep and uh okay so let's actually try to register a user here so we have let's do it super simple now in the beginning input type text a value okay we need some values email we need a password and we need to set these we need email on change uh let's see set email entire target value and we want to do a password password password and that's your button register how does that look use data is not defined use state all right let's just do two placeholders here as well placeholder email password okay and uh last thing here how to focus let's put it there so when we reload the page i thought it was without the focus out the focus how to focus all right i don't know why that is not working anyway so when we on submit handle submit i think handle submit the target prevent default console log function um form submitted let's just see if that works for now i'm going to make this a little bit bigger here for you and we don't want the responsive stuff all right one host form submitted perfect so what we want to do here is actually i try catch and we want to do a wait and i want to import auth from utils hosts and on this auth we can do register email password perfect yeah and if it doesn't work uh register failed and if it did work let's uh and return here so we don't continue and if it if it did work ready situation successful you can remove this one okay register registration successful okay let's see if that user is now yeah it's right here let's say a minute ago perfect so we actually managed to register our user and we want to of course log in the user as well so let's uh let's just see let's actually register the user is complete log in the user so there's two way here one is to log in the user right after it's been registered another one is of course we need to create a new login form so that users can log in through the form but before we do that actually let's wait with this a little bit and install tailwind css we need to make this uh a little bit prettier let's say so let's install tailwind css tailwind css next for next yes right and i think i read a pretty good article here pick a template so let's follow this one so let's install tailwind as a dev dependency next we initially initiate tailwind so it just creates a tailwind config.js let's see how that one looks like uh tail wind it's just um yeah plain tailwind config and i'm gonna activate these two as well so we are set for future future features and we need to add post css okay new file and in that file we want to have this content and i'm just going to copy and paste here so we need to update this again okay right and now we need tailwind css so let's add this one here new file tailwind css and we need these three directives perfect and we want to import where do we want input i think styles should be inside the src folder right so we want to import how to how do i import all right we do something like this but we don't need to do this okay perfect let's see if that works by changing the background color here maybe reload everything load this window as well okay so we have a red background meaning tailwind is activated perfect that's good so let's style this a little bit at least um let's see we don't know we don't need the red background we can do something like div register what do i want to do and let's place everything here in a div class name flex flex call okay i can do the same inside here go to container mx out to and we don't [Music] need so which one is this one red 200 i think it's because i have everything very larger so if i re okay yeah everything is centered and nice now let's style the input fields so we're just going to do a simple style border rounded let's see what happens okay and maybe a little bit of padding so padding x in the x-axis axis for p y 2 maybe that's too much i mean this is better it is better and also do margin in the y-axis of two and let's copy and paste this one and let's get rid of the red actually let's do something here as well maybe shadow yeah so and then we need some padding here as well so px4 looks good p margin y 12 okay that's better and padding everywhere with four yeah that's good register let's do some fancy stuff on this class name um text center uppercase text gray let's do it a little bit gray and text is i think that looks i mean i'm not i'm not a designer if i say something looks good it doesn't mean much but at least it's not terrible and let's style the registration button as well and let's see here so px let's do a background color first in the let's do something nice text white uppercase px for py2 oh wow what's going on here why is it so big why is it so big okay that's better and name flex i uh justify center still too big text asm maybe it's it looks good it's just that yeah i mean i'm getting tricked a little bit by having everything so big but so if i do if i reset everything everything looks so small so okay so i should expect everything to look a bit big so let's remove the small text and let's and hunch uh make everything bigger here again and uh let's actually do what i did before yeah that's gonna be a little bit big that's fine at least the registration form looks a little bit nicer now so [Music] so that's good and and yeah it works so let's duplicate this file actually and do it let's do create a new file called login that's going to be pretty much the same instead of all register we're going to do login and yeah maybe change this login failed login successful we um we want to redirect the user here actually we want to redirect so next yes redirect uh nope we want to do something with a router i think yeah use router push we want to do this constructor equals use router now we can do router history push and let's just push to to the index page cool cool cool so so this is gonna gonna end up here that's good let's see if that works and let's change login here go back register would be nice with a link here so if you are already registered you can click the link so let's do that let's see probably here right div already have an account link login i think it's not um fine and i think yeah i need to wrap it in an a so let's see ref login login and let's do the same here don't have an account register register login well that's nice at least it works but we need the link here as well register login okay now i can switch between let's make the text a little bit pretty as well while we're at it uh class name let's do some padding in the y axis so padding four text center class name text in the go 700 and when you hover do underline bam it's nice and let's do padding top let's do instead there we go that looks much better and text let's make it a little bit gray yeah that's nice i'm actually going to copy everything here and just replace this one and let's see what we're logging so don't have an account register login register okay i can toggle in between here so login let's see now i already created an account before yeah i was able to log in we can actually just check the network request here login we we're sending a post request to auth login and we are sending our details email password and we are receiving a jwt token everything this is all taken care of inside the host object so we didn't don't need to worry about this uh at all like the auth object fixes everything for us it will save the jwt token it will refresh the token once it's about to expire it will also because the auth object is also in the apollo provider here it will take care of you know setting the correct awt token when we're making the graphql requests and we're going to see that in a little while so the next thing i want to do is to create two style styling components that we're gonna use across our app so we're gonna do we're going to create our first components here actually so components then we do we in components i think i want to do layout like a new folder and call that layout new file i want to have layout.jsx and this one is just going to be like a wrapper component so let's see oh you know what let's do like this let's move this one here and remove this folder and react layout and uh this one is going to take let's let's uh see here so yeah child chill drench this is just gonna uh run in the children let's close a few of these tabs here okay so let's just see that this works uh by saying lay layout and then render the children so in login i'm gonna import this one here component layout and instead of this container mx auto i'm going to delay out layout in the bottom here and let's just see what happens happens with the login here login okay so everything is wrapped here now that's nice and uh just for consistency i'm gonna do container and mx out and we don't need to do this okay and i'm gonna create a new component here called called the header ooh and actually [Music] we're going to do a few things here actually we're going to do another one export fun okay let's just finish this one off header return can you okay this one and let's do main main is gonna do container mx and this one is not gonna do that uh instead are we making this hard for ourselves right now maybe no actually not let's do header like so main yeah let's keep it let's do px4 shield okay and header is gonna be our top header uh so in side here we're gonna have like a logo and we're going to have to create post user logout right let's see main looks good children looks good okay what happened here yeah so logo created so let's make this a little bit pretty prettier and maybe we're going to continue using this text white py4 and it's going to be a flexbox item sent center and justify between so we push whoops what happened so we push everything to the right here perfect and we probably want padding on both axes here yep and same thing here click okay item center and class name this is gonna be px4 and this or maybe that's enough actually yeah that's enough we want this as a button or this is going to be like a link to the create post but we don't want to show this if we're not logged in so let's handle that and everything related to login and stuff we use auth is authenticated if we're authenticated we can show this one otherwise we don't show it so actually now we are logged in so we can still see this okay we're not loading let's see login failed register what okay now look uh there's something login should say login register should say register now we can have the actual explanation mark here uh all right so let's if we go to login yeah this is fine we are actually logged in but um this what do you say get resolved after we or before we are actually logged in if we do a reload so the refresh here comes through and we are actually logged in but that's fine let's let's screw let's do the logout here as well i'll click both log out and we also after we logged out let's actually let's actually redirect the user to the login so we're going to use the router again now i'm just copying code from login component here i think this is gonna work yeah so now for let's okay yeah it doesn't happen that's too much but that's fine and let's do let's wrap our [Music] register component as well layout is not defined now it is defined now i can log out i'm get being sent to login that's nice okay and yeah so our login works that's nice yep layout so i'm at home now okay let's think what we want to do next here so let's just try logout you want so i'm logging in i'm being redirected i can see the create post but if i log out this is actually not re-rendered um and [Music] i mean this shouldn't this shouldn't really be a present here or login actually let's remove it i think we can remove it all together so if you log in here now let's reload everything logging in yep i'm getting logged in i'm logging out register login okay that's better now the question is if we want to do this as a private route i don't think so i mean there's going to be two uh sort of two views here one as if you're logged in and one as if you're not logged in i mean with reddit you can still browse everything even though you're not logged in i think we're gonna do the same thing here what we're gonna do though is we probably need to split let's not worry about it too much here let's focus on creating a post or first of all show the user information here creating a post um yeah we can actually this one we completed so exactly let's focus on creating the post here show the user information show user inform mission and then we're gonna list po list posts and delete posts so we have a little bit of work ahead of us let's focus on create a post uh okay i actually had another idea here we shouldn't use this is authenticated here i think i think instead what we're gonna use is let's see react and host what we wanna use is actually something like this we want to use auth and see if we're signed in or not and we want to import this one and so if we are signed in we want to be able to see the create post if not let's not show um no let's not show it same thing here we like if we're signed in we want to show the user and log out if not we want to show something else so we want to show like register or something so we have two paths here so if we're signed in let's show this and if we're not signed in let's just do something like a register now let's see what happens here create a post okay log out i'm logged out i'm going to the index page again yeah register now perfect so it's not going to be a div let's actually do it a link right away so that people can register to our git or to our reddit clone register nice um anything else we want to do here probably in port link register now yeah login or maybe ready to login usually usually we have both right register maybe just to log login login last name px4 let's see how that looks like okay so we can choose between register login if we click register go to register login login perfect you and then okay now we're logged in we can create the post and we can log out and the log out class name actually do a pointer cursor so that looks a little bit better and let's see yeah actually we want what i wanted to do here we're still in the header so uh i want to do user header here actually so we're gonna we're gonna move all this to a different component because now we know we're logged in so we're going to do some querying here so what did i call it user header apollo query i'm gonna do a query here let's see let's just get this back to normal here so what kind of query do we want to do we want to do const get user data so now we're doing a graphql our first graph calculator here query oops let's do this query user so wanna get user data you uh let's see user id it's gonna be a uuid that we're gonna pass into this function we're gonna query users by primary key where id is equal to user id and maybe you're thinking well where do we get this data from and uh how do you know we're gonna do this exact query well i'm gonna show you in a little bit but basically all this is done for you with asura and with and host the the graphql backend api is ready and ready to use and we're going to we're going to fix some permissions here as well but yeah it's gonna be super simple here so we we're just gonna grab the id display name for now and we're gonna do if loading and we don't have any data because we might have some data in the cache uh we're gonna do return loading and yeah if we get an error let's just return div error and console.log error or fetching user and we can log there as well so in user header we know we're logged in because signed in is true so we're gonna render user header so what we're gonna grab here is get user data we're gonna see is it loading do we have an error if everything is fine we'll get the data here and we can actually do user data [Music] and let's do users name let's wrap this one in a div as well we could do this in a div as well use queries not defined import use query from apple look line oh yeah it's not um and this is a permission problem so now we're going to go into the asura console here that's if this is new for you um yeah please follow along as easy as you can but uh with and host we we install something like something called hazara asura sits on top of the postgres database and acts as a middleware and will automatically generate all the graphql api for you so you can see here this is where we have all our tables right now we only have a users table this is where we have our user this table gets pre-created for you when you create another project and you can create any table you want and the the tables you create here is going to be the tables in the postgres database so this is like a database manager for your postgres database quick introduction um as you see as you can see here we already have a couple of the graphql queries we can do we did this one users by primary key the arrow we got we can see no such type exists and that's actually a permissions permissions issue so we're going to fix that one so right now only admin is allowed to query this users table which means you need the admin secret which should be a secret so we we we're not using that but instead what we're going to do is if you're the role user you're allowed to select actually you're going to be allowed to select without any checks because we want to select other users as well and we want to be able to select the username display name and avatar url for now and the user role every new user that is created have this role so this is the default role for users let's see now if we reload everything we still got an error uh expected a value oh okay we need to send in the values for you and let's do that by sending in the variables user id and uh user id here is going to be our user id that of the user that is logged in so by um we're going to get that by uh let's see get table t claim x hasura user id let's see let's reload we still have an error seems like that's not the user id get your ah get claim all right here we go now we have the user awesome but it doesn't look so good class name flex item center that's better that's much better so yeah we can log out we cannot logout we cannot log out because this one should be here okay login we're logged in we can log out perfect if we log or if we go back here we're logged out okay um okay still create post we need to create a post uh where do we have this one we have it here link let's just call this new it's going to be a new post great post it's nice and uh let's duplicate this one call it new this is gonna be create new post this should change cool and you should only be allowed to create a new post if you're logged in so we um but we're gonna just make sure that the user can create a post first here so let's see div do uh i like to type up everything here first type text placeholder title what do we have here value title on change set title oh let's initiate these variables first title a description set title target value uh nice class name py2 to get some padding here and the description [Music] text area set description used it is not imported okay looks looks alright i guess layout oh yeah here we wanna actually use main because we want to center everything here so we can use main to center everything and we need to import main as well cool so everything is a little bit centered here oh actually we want to center everything here as well uh ah let's let's keep it like this for now but we need some uh styling let's keep the same styling as yeah this that's fine um all right title uh with full maybe perfect what styling did we use here oh i mean it doesn't look terrible and now let's handle this form so on submit handle submit and here of course we want to we want to create the post uh prevent let's just see here create post yep and uh apollo mutation create post insert post yeah now we need now we need something in the database where we insert this to so we need to actually create this table here so i'm going to add great table post posts and i'm going to use some frequently used columns here so id created that updated that these are all going to be auto generated for me every time either something new is inserted or something is updated next thing we want to have a title right so that's going to be a type text we want to have a description also of type text and when i have a user id that is the user creating the post anything else we want here right now i don't think so that's fine okay so next thing we want to do is we want to say that okay this user id of this column is actually the same user id as this table here in the users table so we're going to add a foreign key to this users table and we're going to do from user id to id of the users table and we're going to cascade everything it's done if we want to delete anything any unique keys no any constraint no add table perfect and now we want to have some insert permission for the user role so every user that inserts something here they can do so without any checks and they are allowed to insert title and description and we're going to automatically set the user id to the session variable of user id so that way the users are not responsible for setting their own user id but rather the token the authentication token the jwt token and hasura will set the user id automatically so we can be 100 sure that the user id is the user id of the user who's actually inserting the post so i'm going to save that permission and yeah we want to we want to allow to select posts as well but i'm going to wait with that for a little bit so let's so now when we're allowed to insert posts let's do that and inserting a post is a mutation and let's call it post like this and i don't remember these names so usually what i do let's make this a little bit big for you well usually what i do is i do a mutation uh insert post we can do insert post posts objects let's see insert post post insert input type post insert input so inside objects we need a object of type posts insert input posts insert input okay we're going to insert posts or objects we're just gonna do one poster and we're gonna return how many rows we affected so that's gonna be one hopefully or it's gonna be one or it's gonna fail but it's not gonna fail uh let's see great post okay so now we can do try catch console log so if something errors we can say insert post failed and we can do console error error and what we want to do is we don't want to do away to create post here i think we got a very uh valley uh bulls post title description let's see if this works so we're creating a post yeah that looks good create a post created and maybe want to redirect to either the post or to yeah redirect to the post then we need to grab the id as well if we want to do that all right but let's um for now let's just do like this let's see now where are we use mutation is not defined so we're going to do a b post created let's see now so here's our post so you can see we only sent a title and description we sent title and description but all the other fields got automatically inserted so id was automatically generated created that updated at or also set automatically and this is our user id of the user uh who who we are and who created the post so f 5e let's just make sure it's going to be f5e yeah perfect and what we want to do here is we're going to since there's a relationship here between users and posts we can track these relationships that's going to allow asura to track these relationships in the graphical query a graphql api so now i'm just here i'm logged in as admin so i can do anything so let's just do for example posts id type title description so you can see this is our post that we just created now i can like the the final thing is i can do user so now i'm in the users table so now i have direct access to the user object here so i i'm at the post table i can jump to the user who this post relates to and start grabbing data from that table as well and we're going to of course use this uh really soon here but the post is created that's awesome let's see uh show user information great post is done show user information we already did that list posts list posts yeah so we have one post now oh it would be nice to be able to click here and go to the start page nice okay so right now we're not listing any posts we can create posts um but there's no posts listed here i mean we know there's posts but we're not listing them yet so let's just do a naive approach here to to get some posts shown here so of course we need to import some stuff here and then do cost get posts query get posts uh posts let's just do like this id title whoops title discreet create that maybe uh yeah let's start with that actually apollo query get posts if loading and no data we can return div posts loading if our return and we want every console all right so if we have some posts here we can show them post okay let's just uh for now do something like post title um turn maybe what are you complaining about all right arrow loading posts yeah posts not found in type root query this is a permission issue because we're not allowed to see the posts yet so we're going to fix that posts permission we're allowed to insert permission but we're not allowed to select permissions uh select posts so let's do that well we're allowed to actually without any checks we are allowed to uh we're allowed to see everything here right nothing secret about this let's let's reload now still getting an error post is not found am i logged in let's double check that main is not defined and if i reload now i'm gonna be actually logged out and logged in again so okay we're gonna do a small change here i think let's just try this i'm gonna use some code from signed in and let's see now we can do list posts and let's move everything here what i want to do is like what i want to do is when we're logged when we're reloading the page we're not logged in but we're going to be logged in a few seconds like one second later because the authentication module here will make sure we're logged in so when we're first logged in when we're doing this get posts query we are doing it as a logged out user so we don't have access to it but when we're logged in we're allowed to you know request this data so let's just see here listless lost list posts okay okay now we have we have error loading the posts but i think let's see i want to do one thing here let's reload error loading posts um well yes are loading posts you say signed in words not signed in and then we're signing but we get error loading posts and this one won't reload um [Music] hmm okay so let's do like this is assigned in if we're signed in let's list posts and if we're not signed in let's let's also list posts okay i'm just going to test this one let's post two okay so apparently i'm not like even if i that's strange apollo is caching this somehow okay so let's do list post too um oh maybe it makes sense signed in yeah so first it errors out then we're signed in so we're switching from at least post 2 to list post this is not ideal but you can imagine list posts signed in signed out so in a way it makes sense so let's keep it somewhat like this um we're gonna move this to the components folder yeah let's do it new file size sign list posts signed in with list signed in gsx okay so if you're signed in uh you're gonna use this one oh we're gonna use a lot of stuff here as well not this one i think if you're signed in just get posts signed in uh that's this is actually good list posts export function list post signed in right so we can remove this one now and uh i'm just going to duplicate the this one signed out i'm just going to duplicate it signed out i think this is the important part where we change the query name for apollo get post for now they're going to be very similar but soon i mean if you're signed in maybe you want to see which post that you've been uploaded and some of these stuffs okay layout and main right okay let's see what happens let's post we need to import layout is not defined ah [Music] we're not gonna use layouts inside here you don't use a dave instead so it yeah same thing here okay logging out that's fine logging in nice all right the posts uh we don't have much to the post right now we just have the title uh let's see how we wanna have them look something like this upvote the votes downvote title who made the post and description if you if we or if the user is the one created the post we want to be able to delete and edit the post so let's create the markup for this and take it from there all right so for the posts let's first mark everything up in html and then worry about the logic after that so we need like a column here like a yeah like a column here a boat number vote downvote title who the post was made by uh description and i think we're gonna move these to edit and delete buttons just to be underneath here for simplicity so um yeah let's jump into it so we're listing posts as we're signed in and um let's see so between signed in and signed out there's a few different um maybe we so we're gonna do something like post listed jsx with new file post this that and oops where did it go here react component post listed so this is going to be the whole container here so we're going to do class name shadow probably medium and padding six or so and let's use this now in here post listed post listed so we're going to return post listed we'll just say we can pass yeah of course we're going to pass in the post and we're going to set the key host that's going to work and let's just signed in true and we might use that in the future here okay and so now let's just see that we got all the information here so we had a post signed in right so we do post title yep let's do here just last name p y or margin y eight so this is our post seems to be working quite good so now we're gonna split this into two divs here's gonna be the um title and description title title with dip there's going to be the description and inside here we're going to have uh upvote i'm just going to put i am going to vote votes number of votes and then download right we need flex yep let's give this one some space to the left i'm putting left six now let's do a nice upvote button here and i think we're going to use some hero icons here up let's take something nice maybe this one uh let's place it actually in a new folder we're calling svg new file um arrow up oh react come s piggy arrow up right and let's return this one here and we'll use class name here and also to make it easier to import svgs let's create a new file here index g6 where we're importing all the svgs svg from an exporter so now we can import svg here import svg arrow up from and we just need to do components svg sorry not components svg that's it or is it a coupon it's a comport oh nice so now do svg arrow up class name i think we have class name with i don't know what's good with height let's see if that works with a big big one but maybe make it a little bit smaller yeah actually let's keep it quite big uh do a class name here flex flex call item center and let's see oops class so now it's cool hover let's hover it with some kind of background around let's see around can i do rounded full text white okay it looks quite good i mean don't take any uh ui advice from me but transition all easy in this e duration or 15 milliseconds okay so we're gonna put maybe we want to have like a green here okay let's do the same thing for the [Music] downloads red but let's do arrow down and duplicate this one down and import find the arrow down it's not defined we need to add this one here as well it's not exported now we need to import it here all right it looks quite okay it's a number of votes we don't have the numbers here yet so let's just leave it as it is for now let's make some room here for it and i'm thinking if we uploaded this one it should stay green and if we are downloaded it should stay red but we're going to fix that later we're going to move over to title description and the the edit and delete buttons here why is our spacer title description maybe we want to let's modif uh let's not modify let's edit this title a little bit uh example title some longer description let's see there to test reload i mean it's not bad i think it will look good here in a second when we have like it says number of votes for example maybe no i like it i like this this is fine uh and that'll last let's do so this is only going to be visible if we're signed in and post user id equals auth get claim accessory user id that's our id post or we query do we get the user id here we are not but now we are so if we're signed in and the posts i mean and this is our own post let's show some edit and delete buttons yeah and i'm actually logged in here oh yeah i'm logged in and this is my post uh so that's fine let's just see what happens now if we're logged out yeah our lord but we're gonna fix that in a second it's also permission issue let's just make finish this off uh flex items center and px4 do one have some nice buttons here edit this one looks nice duplicate this one edit yes we get it and uh copy this one again class name all right and delete maybe maybe duplicate one and now import as we edit from edit import svg delete from delete cool let's remove a bunch of files that we have opened here and import speaker edit as we get delete now we want to use this one here instead [Music] whoops maybe something like this it's very big but i think it's going to look good all right this is fine edit delete we can create the links here as well link um where do we want to go edit a post post post id what's going on here edit and for this we actually just need to [Music] delete it right away not class name one click delete post did it post uh redirect you uh maybe we no we don't need to redirect the user or we just need to reload query maybe maybe uh maybe apollo takes care of that okay we need what do we have login link delete post well it's not being deleted but the markup is there that's fine that's good and uh what do we have here so it's it looks even better [Music] here let's see yeah what's the next thing we want to do uh list posts all right delete posts okay let's let's do that let's do that right away actually [Music] so const delete post mutation delete post post id let's see the syntax of this query mutation delete uh post or we can do delete posts primary key let's see what does it return okay and maybe just ready let's do this one okay import graphical tag we also want to import use attention from a client now we have everything we need here to actually delete the post delete post what only set up delete post post id is post id and if we fail console error return [Music] failed to delete post cool let's see what happens here let's see what happens here delete post fail to delete yeah we don't have permission to do that so let's fix it delete and now we want to be careful because we only want users to delete their own posts so user id on the post needs to be equal to accessory user id so that way we can make sure that users are only allowed to delete their own posts let's try again i think that so if i reload everything here yeah there are some posts so let's do one thing here now that's fine that's fine either we re um request let's see but word we don't know let's do this as a subscription instead i used to do s like this so that way when we delete something it will automatically fetch the posts that are not deleted i think that's it basically let's can i create the post great post hey deleting it oh it's moved okay perfect hello world um when we click here i want to be redirected to um to the starting page so let's do that as well login i think the use router maybe we can call this something else new doesn't matter but router push okay let's let's try now perfect i can see the post i can delete it we can even do just want to show you so to the right here we don't have any posts right but i'm going to create one hello hello [Music] on the road 3 so you can see it all gets updated everywhere subscriptions are cool and if i delete something let's try to log out and create a new account you you successful okay post loading okay so we have an issue here i'm shouldn't be allowed to see this one as this user let's fix that one right away post listed if post user ready so let's see what these variables are causal log find in post user id get claim let's focus on this one here now signed in true wait okay i'm not sure if this and this and i think i should do like this right oh and everything it's wait it should be fine okay all right now it's good so if you're the same user you can see it but if you're not you can see it um so i can delete this one and let's get the data from for everyone okay that's good delete posts working edit posts next one two three one two three edit post something edit and now we need to do some ju next year next year stuff i think pages um we need to do post in post we need to do slug and in this one we need to do edit i think uh 22 page could not be found so we have po post rename oh yeah okay how do we get the um slug here next yes get slug dynamic routing okay seems pretty straightforward and we need a slug so let's see uh it's not slug actually it's id but let's call it slug for now yeah getting there getting it here let's think now apollo query get post um post id i'm gonna be slug we want to get the post so const get post query get post post id it's going to be a uuid it's going to be required post posts by primary key uh for now we just need a title description let's see we're gonna import some stuff we're gonna import use query and use mutation let's see now let's see now so once the data is uh fetched i want to send it to another component so we're going to do if loading returned same with error um once we have the post we can send it to edit post and i'm actually gonna create that one here function return it's going to be very similar to this one so i think i'm just gonna copy everything the only difference here is going to be that we fill in the title and description here and we're gonna have a you apollo mutation so that's gonna be update post update post session update post post id and post we're going to look at the type up okay i'm doing a lot of things here and simultaneously but um a sync function handle submit try catch uh this is gonna be the same post id and the post is gonna be title and description and let's see now if it doesn't if it fails we're going to return alert failed to update post console error and if it succeed let's just let's just use a router again and push to the starting page okay let's see let's take it carefully now we need to fix the update post notation here other than that i think yeah it did post yes all right we just need to fix this one mutation update post by primary key post set input post set input yes perfect uh update what's going on primary columns ah okay how does this work update po post a primary key primary comes to do this no don't do this yes okay i think this is good enough okay update post mutation update post we're sending in post id and post that's going to be the new post updating post spy primary key and primary columns is going to be id post id and we're going to set post and of course post id is going to be post id and the post here the new post we're setting it's going to be uh title and description it's going to be the new title and the new description where we're taking out of this form let's see if it works close but no cigar data okay let's see what's going on okay of course it's only error i didn't fix no such type exist in the schema uuid what get post post id is a slug well it's the id but we call it a slug i don't know why it's in complaining no such type exists in the schema uid i'm pretty sure it exists but if you say so let's try it okay the autocomplete doesn't complain [Music] so we're sending in this and i'm able to get it and it shouldn't be a permissions problem so what can it be what can it be am i not logged in maybe maybe that's the issue i'm trying to edit what nope same issue expected value but not very well this is a little bit better uh yeah i should wrap it inside variables okay that's better layout okay edit post so we're gonna do uh three two one or hello fail to update post post set input networks in the schema ah maybe it's a permissions problem because we're not allowed we're not allowed to update anything here so let's do that so we need we're only allowed to update our own posts we don't need to check this because we're only allowed to set title and description save let's add it again primary columns is expected no such are primary pk columns yeah now it works hello one two three so a new uh new updated title okay okay yep all right we can update the post that's amazing that's amazing edit post upload download is that's going to be our last thing yeah okay so let's uh let's deal with the upvote and downvote in in a second okay so as you might have noticed i haven't prepared much for this video i'm just going along and so you've been seeing all my mistakes and how i how i fixed them and i think now it's going to be one of these sessions as well we're going to implement um we're going to implement how to upvote and download the post and make sure that the upload and download numbers are correct and i have like a vague idea of how to do this so let's try it out so let's start by creating a table post up votes so here we're going to have id uh when it was to create yeah we can have updated as well what post is either being uploaded or downloaded so we have uid here what user is doing that photo download and also if it's upload or download so vote type maybe we can just put this text for now um wait a second maybe we want to have vote type as an integer and do plus one and minus one hmm that way we can just sum all the um yeah let's do that so vote type can be plus mine we can we can probably make a check constraint and then we can just summarize uh vote type for a post id yeah i like this approach okay so let's add the two foreign keys um one to post post id id and uh if the post gets deleted all output and downloads got delete gets deleted save users user id equals user id nice and where we only allowed users to upvote and download once per post so the combination of post id and user id user id is going to be unique and then maybe let's add the table here and do the check constraints afterwards here no more how do i do [Music] okay i can just do something like this second name up vote type type check so vote type equals um one or both type equals minus one okay seems to be working okay let's set some permissions here right away so update permissions anyone can um anyone can update uh sort of sorry insert and they are allowed to insert vote type and post id and we're going to set the user id automatically yep select without any checks and let's see we we can allow everything and also aggregate queries which is important limit number of course we don't ah maybe let's fire for now we can go back to that if it's gonna be a problem also we're gonna allow people to update of course if you you know upload something and then you realize no i want to download it or vice versa vice versa so if you just write is equals to user id you're allowed to change your vote type so you can go from plus one to minus one all right then delete how do you delete so upvote and then upload again that will delete it in that case you're only allowed to delete your own stuff cool we have everything in place now let's track these relationships between upvote or sort between post up votes and users and posts so track all cool and so what i'm thinking now is we're gonna do uh upsert absurd huster so basically we want to insert the upvote or downvote but if there is already upload and download we want to upsert that um row to change the upvote to a download or vice versa so let's see here uh insert update selected console collectors on yeah exactly so insert uh ops or yeah in with what they're doing insert let's see mutation oops annotation insert post upvotes and let's see the documentation for this one yeah there's actually on conflict cool so on conflict the constraint we're getting and what columns we want to update yeah perfect all right so let's um let's actually upload something and let's actually you know get the correct numbers here let's start by getting the correct numbers so signed in posts are we actually missing something where we're missing who's made the post um let's do that as well so let's do that first user id display name posts loading and in post listed under the title um let's do a small one here py2 maybe created by post user display name no that was quick and easy now i want to grab some more data and i'm actually going to move this whole query over to the graphical here to test it out and just a query here instead um okay we're not using any query variables nope so what i want to do for this post i want to agree post yeah exactly post up but aggregate uh aggregate i want to summarize uh vote type there that's exactly it probably because we don't have any output or downloads but that's fine we can work with null values let's just i'm curious to see what else we can do we can summarize we can count so that's the amount of votes so though so a post could be at vogue it could be at some zero with a lot of accounts that might be interesting to see like if 50 votes downvoted deposed and 50 uploaded the post the sum will be zero but the count will be 100. some variance average yeah let's go with this for now i'm just going to put it here for now so we have the data let's see if we can load this data still we can good and yeah let's let's use this one now here instead so it's post aggregate a sum of thai votes was that correct aggregate some vote type both type and if this one uh yeah it's gonna be a long one here but if it's not set or if it's set we're gonna use it if it's not set we're gonna default to zero right so otherwise it's gonna be zero all right now let's actually try to upload this on click um let's just do vote post vote one and use a poll limitation post vote let's hear insert post vote const insert post vote so this is where we're doing our vote it's going to be a mutation insert post vote it's actually going to be an upsert um yeah so let's call it up search post vote um and we want to let's see here i want to have the post id it's gonna be uid and one of the vote type type vote vote type it's going to be a integer so let's see here in what did we have here before maybe you can find it in history imitation insert post outputs up did i call it upvotes should i should call it votes post votes yeah that's better insert vote post votes one can i do on conflict on this one though i can cool so object is going to be post vote on conflict constraint this one so if i get a constraint if the post id user id key this is a uni i think this is a unique key that we set uh just recently yeah unique or primary key constraint uh so if we get this uh let's see here let's just finish up this one so id [Music] on conflict constraint update columns update columns uh how do i do this one yeah i want to update both type right this is a bit of a complicated mutation but what it does is i'm trying to insert a vote either or not voter or download and if i get a conflict that i already inserted a vote for this post with this user i will get a constraint [Music] constraint error or what do you call it conflict conflict yeah i'll get a conflict on the constraint so instead of inserting i will only update the column and i will use a vote i will only upload vote type the vote type column so maybe i have so then based on based on this information here that i inserting let's let's see if it works um okay post vote it's gonna be another one that's better pause vote cool insert upsert let's call it upsert up absurd post vote upsert post vote and let's actually try to do it now [Music] try catch fail to upboard up cert now we're doing the voter variables and this is going to be let's see now post vote post and here we're gonna post id we um let's see here yeah let's see let's see what happens error loading posts oh i'm signed out we haven't fixed this one yet all right let's clear this console i have a feeling we might see something useful here what it worked what amazing okay let's see if i can download the post oops so instead of vote type one we're doing minus one yeah there we have it i can upload i can download and um if i haven't uploaded or downloaded um it will insert and if i have already uploaded uh if i do a download it will replace our vote with a download so you can see i'm going from minus one to one so there's always gonna be like right now there's only only gonna be one entry here so this is me on this post and i'm up voting but maybe i changed my mind and i downloaded this post instead so if i rerun the query here you can see i changed it to a minus one just to recap really quick upsetting the post so i'm trying to insert if i got a conflict if i already inserted something here i will only update the columns both type which means i will only update this field here with whatever i send in so that's going to be plus one minus one and i'm not allowed to do anything then plus one to minus one so i can't you know send in two hopefully uh fail to upload yeah you see check constraint validation neural uh for relation possible to violence check constraint vote type check so it's not like i'm only allowed to send it one or minus one okay so is there an easy way now to mark this as green or red background um for that we need to we need to select we can actually do post up oh wait um so if i let's just make sure that the names are correct some modify ah title what i'm worried about is it still says past upvotes here and we changed that to votes only so posts yeah you can see post up votes post uploads aggregate so even if i change the column name it didn't change the names of the graphql a thing here i mean it's not the end of the world but i think i can change them here uh yeah actually this is wrong post vote aggregate function post boots now let's see hmm or maybe i'm on the wrong i shouldn't change this one i shouldn't what be nice to you know reset the default uh probably ah okay what i'm not sure what's happening here but let's just leave it as it is if it works it works what i want to do now is actually query and i want to get post up well yeah where user id is equal to uh to the user id there and let's get the vote type i think that's enough and the user id is of course going to be the user making this request and we're getting the user id from the claim here now let's see what we have in a post so a post will contain yep so it will say vote type -1 and this entry right here will only contain one item so we can actually um well one or zero items um so let's let's introduce class names and [Music] make sure that the class names all correct let's see now post post uploads length is more than zero or we can do equals one uh so we now know we have a vote so we can do a constant vote equal post post uploads and now we can do cost up vote classes equals class names uh oh we can actually do yep background green to let's do 200 uh if let's see now wait if um vote vote type equals one now i just need to remove everything here place it here and let's use this variable here as a class upload classes um maybe i can do something like this so we'll type i'm not too sure about this but so if there's something here either or else noodle let's see what happens so let's upload this oh yeah awesome i like how i get surprised every every time something works down vote classes so this is gonna be the same thing but minus one uh not the same because we're gonna do red and where do we have this one here down both classes bam let's see yeah that looks pretty good that looks pretty good let's see how it looks from a different perspective from a different user so i'm logging out let's see if i remember yeah so maybe we're two people uploading or one uploading one down voting two people down voting i guess this looks all right i can't edit the post here but i can edit awesome cool okay i think the last thing we want to do is make sure that it looks somewhat okay if we're logged out because right now we're not our no air loading post we're not allowed to see anything here so i'm going to take a quick break and be [Music] back all right so let's uh fix let's fix the log out part of the page so if you're logged out you still want to browse this reddit clone you're not able to right now so we're gonna fix that so if you're logged out you're you should still be able to see everything and you should be able to see how many uploads downloads the title description who made the post so let's see if we can manage that so we have our uh let's remove this signed list post assigned in and our request as signed out is going to be a little bit different uh it's going to be pretty much yep we're going to just remove this one uh so let's see sign out right now we have this one so let's just copy everything here remove this one we don't need that one anymore and we're not going to use that one it's going to be signed out we're not going to send any variables here we're going to use a subscription instead of a query uh loading error loading post and then we want to do something similar to this right i want to use our post listed component with sign in false all right let's just see how it looks doesn't look too good error loading post and the reason for that is if you're not signed in you're not allowed to see anything so we're gonna fix that so uh there's a special role public called public so if you're not logged in and you're making a request to the graphql endpoint you will be regarded as the public role so we can use this public role to set permissions for logged out users so okay let's make this a little bit bigger here okay so for post the public role is allowed to see everything and the public role is also allowed to select without any checks display name yeah let's okay id maybe as well because we're fetching that avatar url we're not using this in this project but we're gonna you know maybe want to use it in the future post upvotes uh select without any checks allowed to make aggregated aggregation queries and i think we will allow to select everything here now let's see what happens if we reload we didn't get the same errors previously but instead we're missing this component are we missing no we're not using oauth that's right um error what yeah this is probably because this is probably because we're not logged in and we're doing some exactly um so i'm gonna let's do like this we're going to do something like votes here instead and then we're going to do this logic here so let's say if post [Music] a vote up let's agree in post we can do this thing here so votes yep looks good else wait what am i doing that's not the issue we're having the issue we're having is actually i think it's this one yeah okay so maybe just that will solve it ah something like that can i do that null unexpected token and let's do like this so if this one exists we can we are probably sure that one exists otherwise let's do null that's probably going to solve our problem yeah so exactly failed to upload that is because we're not logged in so we're not actually allowed to upload and download so instead maybe what we want to say is something like login to upvote but at least now we can see the posts and i think we had some like a little bit of margin here right yep okay let's fix that last thing where if we fail to upvote fail to upload app must login to up mode and for downloads you must log into down but i think that's it i think that's it so we can register we can log in we can see what post we've uploaded we can change our vote uh we can create new posts we can edit this one we can remove i don't want to remove this now like a logout yep i think we're i think we're done uh thank you for watching this video and if you have any questions just leave a comment below i'll try to answer or i will not try to answer i will answer all comments if you comment on this video and if you enjoyed this video give it a thumbs up and let me know so i maybe i'll make more videos like this in the future thank you thank you very much bye-bye
Info
Channel: Johan Eliasson
Views: 3,617
Rating: undefined out of 5
Keywords: react, javascript, fullstack, graphql, hasura, nhost, nextjs, tailwindcss, apollo
Id: A7rAGsN6WYc
Channel Id: undefined
Length: 159min 20sec (9560 seconds)
Published: Tue Oct 20 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.