Chakra UI Component Library, Next.js, & GraphQL With Apollo Client Part 2
Building a GRANDstack Podcast App: Episode 6
In Episode 6 we continue our focus on the frontend of our Next.js React podcast application by adding a podcast search results view, and manage playlist functionality using Chakra UI, GraphQL, & Apollo Client.
Links And Resources#
- GRANDcast.FM code on GitHub
- Chakra UI docs
- Apollo Client docs: executing queries manually with
- Apollo Client docs: optimistic UI
- Apollo Client docs: updating the cache
hi everyone welcome to the neo4j stream my name is will and today we are continuing with our grandstack podcast application so this is a podcast application built using graphql react apollo and neo4j database let me drop a link to the github project cool so there's a link to the code in the chat um if you've been following along this is now the sixth uh episode uh we've built out our backend api uh the graphql piece using uh the near particular fql library we're using the podcast index for podcast search so we're sort of wrapping the podcast index api with our graphql api and then in the last couple of sessions we focused more on the front end of the application so we're using next.js which is a react framework and we've been working to add things like authentication and sign in on the front end and in the last session we focused on using the chakra ui component library to add some front features last time we got done with the episode view so the uh episode feed for a user so when i sign in i see here's all the episodes that i've subscribed to episode of the podcast that i've subscribed to and then i can assign those to a playlist that's as far as we got last time so what we're going to focus on today is the playlist view so being able to select a playlist create a new playlist view all of the podcasts in that playlist and then also front end for the podcast search functionality so that i can search for and subscribe to new podcasts so that's what we're going to cover today so we'll be using shocker ui again we'll do some apollo client querying our graphql api we'll have to think a bit about maybe some optimistic ui uh features in apollo client that'll be a good one to touch on uh and so the goal for today is to add the playlist sort of management functionality i guess you could call it being able to view all of our playlists view all the episodes in each playlist and create new playlists and then the podcast search result view so that's the goal for today hopefully we can get through that feel free to ask any questions that you have in the chat and i will try to post useful resources there as well before we get started um i want to talk about just a couple of interesting things going on in the neo4j and graph database world so one of those things is the nodes conference nodes is the neo4j online developer expo and summit this is kind of like the annual [Music] online neo4j developer focused conference the the conference itself is in june but one of the deadlines coming up fairly soon is if you're interested in submitting a talk so nodes we love to hear what folks in the neo4j community are working on uh so we would love for you to share your graph story with everyone at nodes uh it's a really good opportunity to present a project that you're working on something interesting that you've you've learned some new use case that you've found for graph databases in neo4j so i'll drop a link in the chat to the nodes 2021 site and then also i'll drop a link for the call for proposals so this closes on april 5th so that's a few weeks so if you're interested in submitting a talk please submit it by april 5th and if you're curious sort of working on your proposal have some ideas what would make a good proposal uh check out some of the uh drop-in sessions on the neo4j discord there is also a new podcast that lou and i are co-hosting called graph stuff fm and this launched just this week so we've launched just the the first episode i'll drop a link to that in the chat here graphstuff.fm so the the goal for this podcast is to really focus on uh some of the more technical aspects of neo4j so looking at neo4j from the developer's perspective in the podcast so we'll cover things like you know what is the neo4j graph platform how do i build applications with neo4j how do i use graph data science these sorts of things so we've recorded a few episodes the the first one uh was released uh yesterday or earlier this week and it is focused on how to sort of think about building your proposal and talk for a technical conference so this fits very well with the cfp deadline for nodes coming up so check out that podcast let us know what you think we will be doing episodes uh probably uh once a week i think for the the foreseeable future here like i said we have a the first few uh recorded already so that should be interesting but definitely let us know what sort of topics you'd like to hear on the graph stuff neo4j podcast cool so with that let's fire up our application and see where we left off last time so i have neo4j desktop running with my database from last time so we have some users actually let's take a look at the data model really quick seven four seven four yes so here's the data model we have podcasts that are connected to episodes episodes can be in a playlist and a user subscribes to a podcast and owns a playlist so the data model is fairly simple so far if we look at some of the podcasts we have here we can see podcasts have episodes here's a user that subscribes to this podcast this user owns some playlists and we can see some episodes that have been to assign had been assigned to various playlists that's the graph data model uh let's to our api and start our graphql api this is running on 4001. cool so we can see the schema for our graphql api we have a few different entry points one is podcast search which you're going to make use of that today so that returns a podcast search result and this remember this podcast search result data this is coming from the podcast index rest api so this is not returning podcasts that we have in the database we only parse a podcast feed and add it to the database when the user subscribes to it we have playlists that's another entry point that we will be using uh so every playlist has a name and then an array of episodes that have been to have been assigned to that playlist and these are authenticated well some of these i guess are authenticated query fields so playlist for example this requires an authorization token so if we go through the login or sign up mutation that returns an auth token which is a jwt json web token it needs to be added as a bearer token in the request header so that's how we make an authenticated graphql request we add the authorization token here in the request header so this query we're going to search for all of the playlists that this authenticated user and this is left over from last time i think this is our jenny cat user maybe but here's the playlist that we have so we have one called breakfast time it has a couple of episodes we have another one called another playlist called must listen that has a bunch of other episodes okay cool so that's the graphql api now let's go to our next app and start that and we'll see what the front end looks like that's running on localhost 3000 okay so the first thing we need to do is sign in i'll sign in as jenny cat cool and this is what we built last time zoom out a little bit try to make that readable this is what we built last time so these are the episodes the most recent episodes of the podcast that this user subscribes to and then i can see which playlists these have been assigned to i can assign them to other playlists i can look at the show notes and i can play them which i can hear that but uh i guess that's just to my headphones okay cool so that's that's where we left off last time so we have the episode feed but what we want are now the playlist i guess is is probably the next thing that we want to to add so when i click on playlist here i think this will give me a 404 yeah we haven't built this page yet so when i click on playlists what i want is because playlist is this is an authenticated part of our graphql api so in order to successfully query the playlist query field you need to be signed in you need to have attached that json web token to the header of the graphql request so if we're not signed in we need to just show the the sign in form and then if we are signed in uh i guess we need to fetch all of the playlists for that user and all the episodes for each playlist we can that's not going to be a ton of data we can probably just do that once when the when the page loads and then we need to give a drop down for the user to select the playlist they want to view episodes for show them the episodes kind of like that episode feed here where we were showing just all here's all the episodes for the podcast the user subscribes to basically that sort of view and then we also need to allow them to create a new playlist so let's get started with that i'm going to go into the next app directory in pages and one feature that's really nice in next is the file based router so when i add a new file in the pages directory that maps to a route by the file name so podcasts dot js has react component that is served when i go to slash podcast so when i create playlists this will export a react component that will be at flash playlist so export default playlists and let's see we probably need to import a few things well we said that if the user is not signed in then we want to give them the sign in form so let's import that component sign in from components sign in we're also we know we need we're going to need the episode component since we're showing like a list of episodes and we will need our use auth hooks that we built a few sessions ago so this is this has the functions for sign in sign out that the sign in form uses we've already built that in the sign in component but what we want to use use auth for here is to detect if the user is currently signed in or not so that's how we know to display the the sign in form and what else we know we're going to use some graphql queries so let's import gql use query so we're going to run a query when this page first loads to find all of the playlists for the user but then we're also going to need to execute a mutation if the user wants to create a new playlist so we'll pull that in from apollo client and i think that should be good for now so let's say to start off we will actually let's start importing some things from chakra remember we we introduced shocker ui last time so chakra is a react component library that has some great styling features built into it uh we are going to need a form form i like to start with the form control component even if i and this is mainly for uh like showing form context and validation like if there's errors and whatnot so we have that functionality built in there but it's also a nice sort of grouping for a form and chakra that i like to use so let's start pulling in some of these things so the container is maybe a place to start here that just sort of applies some of the the base styling of our default theme for chakra and we know form control and select and a button probably some of the basic things we'll need we'll probably add some more imports there later that's fine uh chakra ui reacts okay so we want to wrap all this in a container so that nice styles are applied and then if we're not signed in so let's grab the is signed in function from use auth so if we're not signed in then we're going to render the sign in let's get our multi-line back here just the save on formatting is sometimes smarter than we need it to be that's fine okay so that and then if we are signed in this is signed in there we go i turned off all of the intellisense and autocomplete things in vs code since i think it's easier to not have all of those pop-ups on the live stream but i guess maybe that leads to a few more tendencies to to make errors but we'll figure it out so if we are signed in let's wrap this in a div this is going to be initially our form give it an id playlists so here's our form and then the form is going to have a so we want like a select drop down over here and then to the right of that we want to have a button so i like to use the flex component for that that applies flexbox css so then our select needs a placeholder value select playlist and then when i select a new playlist in the drop down i need to handle that change so the on change handler gets passed in the change event and let's set the selected playlist so this is going to be a state variable that we're going to create in a second so this selected playlist state variable does not exist yet e dot target dot value so when i select something from the drop down we'll update the selected playlist state variable and then initially let's just put in a placeholder for the options since we don't know we're going to have to run a graphql query to find what the options are for the drop down so we don't know what those values are yet so let's bring in use state from react so use state this will allow us to create state variables and we want to create selected playlist so selected playlist that's the name of the state variable and then we also get set selected playlist we'll call it in this tuple that is returned from use state and we need to set the initial value for the state so use state says hey we want to create a new state variable this is the initial value an empty string and we get back this tuple that has the state variable and then a function to update that state variable which is what we're calling in the change handler for our select drop down okay let's see what that looks like so if we go to playlist it says hey you're not signed in so we need to sign in we sign in and get an error that flex it's not defined we'll pull that in anything else using form control flex i think we got everything else cool so now here's our drop down we can select our placeholder value foobar that's fine nothing happens okay cool um the next thing we said after this select is that we want um a button over here so we want a button that we can click to create a new playlist so let's add a button um let's use an icon add icon i think so chakra includes uh icon icon button or the icons here we go chakra includes a bunch of icons that we can import so the add icon just a big plus import add icon from chakra ui icon so this comes in a different package and let's get that some margin so ml it's a style prop that is short for margin left so we add some margin to the left of the button so it looks a little nicer okay nothing happens when we click the button that's fine we'll figure that out so i think now what we want to do is instead of having our sort of dummy default data for the options in the drop-down let's actually run a graphql query and see the playlists for the authenticated user and populate the drop-down so up here we're going to define the graphql query for that let's call this git playlists and this is going to be jump over to playground something like this so we're just going to grab all of the episodes for every playlist when the page loads i i don't think that i don't think it makes sense to only fetch the data when a user selects a playlist i don't think we're going to have that much data that it's too much to bring back but we do need to bring back the fields for each episode that we need to then pass to the episode component that we built last time to render the episode component so we need the id the title audio that's the audio file summary is the the description you need the image pub date and we'll format that to grab the individual day month year so that it was published and then we need to know what podcast this episode belongs to and that podcast has a title and an image so i guess we probably we don't need the image here well i guess an episode can have a different image um anyway we'll go grab it okay so that looks like what we want let's copy this and that's going to be our get playlist query and we want to run this when the page loads so data come back from use query get playlists that use query hook will also return if there's a loading state if there's an error but i think i think we'll just grab the data and just check to see if there is a playlist in the data to iterate through i think that's probably fine so instead of having this fake option value we're going to if we have data and if we have playlists let's map over the playlists and for each playlist return an option or the key and remember the key is needed by react so it knows which anytime you iterate or map over a list like this where each each element in your array that you're mapping over returns a component you need to assign a unique key to each of those so react knows how to handle those in the virtual dom so the only sort of thing we have unique for a playlist is just the name and that's also going to be the value for the drop down option p dot name okay let's see if that works so we should see the playlists for this user cool and i do great so here's the playlists that exist for this user who signed in great the next thing we want to do then is when we select a playlist we're currently we're updating this selected playlist um state variable so i think what we need is like a filtered uh filtered playlist variable where we're basically just filtering uh based on what playlist we've selected and then the episodes in that playlist are we want to render in the list so let's create a filtered playlist and this is going to be if we have data if we have playlists filter that array and what are we going to filter where the name of the playlist equals the selected playlist state variable and then this gives us an array because we're filtering the array for elements that match this condition so we just want to select the first one the first element in the array okay so filtered playlist is now down here where we want to then i guess after the form right after the form we'll use a stack stack we use a stack component from chakra which is really good for rendering lists of things and specifically we'll use the v stack for stacking things vertically so this will be a v stack and then we're going to map over our filtered playlist so if we have episodes in that filtered playlist we will map over the episodes and render a episode component remember we need to give it a key we have the id of the episode in this case which is the unique value and then pass in the episode value as props and then if you remember the episode component also takes a playlist and that's so that it knows when you click the uh well we'll see it in a second here when you click let's take a look here we go when we when we click the plus button it needs to know the playlists data for this user so that it knows okay is this episode in this playlist it has the logic in the episode component to figure that out uh if it is then it displays this check mark next to it and then uh all the episodes for the user so you can assign that episode to a playlist so that goes in the playlists prop which we have in data dot playlists cool let's see if this works so if i go to playlists and select breakfast time i get breakfast time great jogging great so i'm getting the episodes that i have assigned to those playlists let's add maybe some margin or uh spacing i guess is what we want here on our v stack and yeah maybe some margin at the top there we go that looks better okay so we have our playlists we can view the episodes assigned to each playlist the next thing we need to do is when i click this button i need to create a new playlist for the user and then i need to show it in the drop down as soon as the user creates it so for the ui component for that i want to use a pop over which i think is down here in the overlay yeah so we want to pop over and i'll pop over so there's a button i click it and we get the popover that shows up and we can put form data and put any elements we want inside the pop-over so i don't think we need something that looks that fancy but just a yeah something like this so we'll show a form when i click that plus button and just ask the user for the name of the playlist that they want to create and then we'll put a button in there that says create or something like that and when they click it we then need to run a graphql mutation to create the playlist so let's start there and define the graphql mutation that we need to run so if we look in graphql playground and if we look at create playlist there's a create playlist mutation takes a name argument and that's it so up here and typically you would define your graphql queries in in one central file maybe and reuse those i like to include them in the component files like this but uh whatever your your preference is there whatever makes the most sense especially if you're going to be reusing graphql queries it makes sense to include them in their own central file somewhere but here we're going to define the mutation and we need to declare some graphql variables so let's call this create playlist wrap this in the gql template tag so this is a mutation call it create new playlist and here we declare the graphql variables that we're going to use say call it playlist name which will be a non-nullable string and the mutation field is create playlist argument name that is our playlist name variable and then we'll just return the name of the playlist that we created and down here for our mutation create playlist that is the function that we will call to execute the create playlist mutation and this tuple also includes the data and error and loading but i we don't really care about that i think in this case we're just gonna sort of fire and forget the mutation okay so that's the graphql mutation when you have the create playlist function now we need so here's our button our add icon button now we need zoom in a little bit maybe that's too big but we'll try that now we need our pop over so let's go over to chakra this is a good example this one yeah it's maybe too complex let's look at sees this one as kind of a base example so we have a pop over and i'm going to keep the button here that's going to be our popover trigger so we'll put our closing tag below the button so we have the popover and then we have a popover trigger and the popover trigger is our button we've already created so that button is going to be visible but the rest of our pop over is going to be hidden until we toggle it and that is that content is in the popover content component so there's a pop over arrow and a pop over [Music] close button and i'm i'm just following this this example over here in the shocker docs so the pop over close button and then a pop over header and in the header we're going to say create new playlist and then we have a popover body and here's where we're going to put our form let's do a form control id is new play list in the form control this is going to be fairly simple we'll have a text input and here we need for this change handler we'll need to define another state variable let's do that in a second here so uh when i start typing in the form the change handler gets called and passed that event so we're going to say set new playlist so we're going to create a new state variable called new playlist set new playlist is the function to update that state variable and the value is value the text box uh let's create that state variable new what did we call that new playlist and set new playlist and set an empty string for the default there okay so we have an input and then i guess we also need a button then so this is inside the pop-up remember so something like this so this pop-up comes up and it says create a new playlist what's the name of your new playlist whatever then a button to actually create the playlist and run the graphql mutation so we'll have a button that says just something like create but on the click handler we want to call the create playlist function so this is create playlist right here this is going to execute our create playlist mutation which we defined here that takes a graphql variable playlist name so we want to be sure to pass the playlist name graphql variable so variables takes an object playlist name is new playlist so new playlist that's the state variable that we are use are using to store the value from that input form field okay let's see if this works oh yes a lot of things that i forgot to import from chakra so what did we have we had a pop over we had a popover trigger we had popover content we had pop over arrow we had popover header we had pop over close button uh i don't think i'm forgetting anything but let's find out we'll sign in pop over body we forgot probably something else too input yes uh well let's do a scan here form we have input button form control okay this still works so now let's click this so this should trigger our pop-up cool create new playlist oh let's add some margin in here [Music] and here's on the button so margin at the top mt there we go let's call this foobar create okay i don't see it in the list but if i go to home i can see that now i have foobar as an option so if i go back to playlists now i have it as an option so what's going on there well let's take a look at the apollo docs let's bring those up we want apollo client react and down here in fetching [Music] okay so what was going on here so we'll come back to the docs in a second here so when i run this mutation i'm creating a new playlist but the data for rendering the playlists well that's that's already been fetched and apollo client will cache that data in the apollo client cache so that it's not sort of constantly going back to the server to fetch that and because that data has already been fetched cached and is used to render the view when i create something i need to tell apollo clients to update the cache and use that new updated data when i then go back and look at the values in our drop down so how do we do that well in a lot of cases so let's see caching query results oh actually we want to be in the mutation section updating the cache after mutation yes so in most cases so like the zoom in a bit in the docs here so if a mutation updates a single existing entity apollo client will automatically update the value for that entity in the cache if you return the id field of the modified entity right so if we're updating something that already exists we just need to return the id field and apollo client is smart enough to update the cache but that's not the case here because we're creating a new entity so what we need to do is then update the cache explicitly um update the cache explicitly when we run the mutation so in this example when the cache is updated or when the mutation fires that is updating the cache adding the new value which is what we're going to do so over here in our call to create playlist we are going to pass in a function for update so update is past a cache proxy i guess is a way to think of it so like it's a proxy for the apollo cache which we can then read from and write to so we're going to do both of those things we're going to read from the apollo client proxy cache to see okay what are all of the the playlist values and then we're going to add our new one to it so first let's grab some data so that will be proxy.read query where the query is our get playlist query that we defined above so what are what's in the cache for the get playlist query already and then we're going to write to it right to the cache update the cache for the get playlists query and the data that we want to update is specifically the playlists which is an array and so we're going to do an array spread so we want to include all of the existing playlists but then add a new playlist and this is an object apollo always adds the type name and this is used in the cache so we want to be sure to include the type name of this which it's a playlist and it has a name which is new playlist so now let's try this again so now before we had to sort of refresh the page to see the playlist that we created but now let's go to playlist so we have we have fubar and fubar 2 so let's create foobar 3 create that and now that should show up in the drop down yeah cool so i didn't have to reload the page i have foobar 3 and here let's do foobar four make sure this really works yep there it is cool so we're updating the apollo client cache when we run that mutation so that will then update in the ui this is uh this idea of optimistic ui that we're updating our ui without really waiting for the results of that mutation to come back uh so we're optimistically updating it assuming that that is going to work cool and let's test to make sure that for a new one so if i go back here and let's assign this one this all in podcast to foobar four if i go to playlist foobar four yep i have it cool so that works cool so that is the playlist functionality i think that's everything we want for the playlist the next thing we want to do is add the view for podcast search so currently if i go to slash podcasts i have just a very uh a very simple list here of all the podcasts in the database and remember we only add podcasts to the database when a user subscribes to it so what i want is something that's using the podcast search query field here so that a user can search for whatever their whatever podcasts are interested in view the search results and then subscribe to a podcast so we're going to let's start by updating this podcasts page since we already have that and i don't think it makes sense to just show a list of the podcasts we have in the database since that's that's not really relevant for the user so we'll change this to be podcast search instead of just show all the podcasts and i think we'll probably also need to create a podcast component or something like that okay so let's do a few things let's first change the podcast query here and instead use podcast search uh and we need to define graphql variables here so we'll say we can make this a little bigger a little more legible so we'll say query podcast search and we need a search term is of type what non-nullable string i think and then we're going to run the podcast search query field is our entry point we have our search term as a variable and then i want to return itunes id title description the feed url artwork the image and any categories that the podcast is in i guess that's that's pretty much all the fields that we have looking here so let's see if this works let's add query variable here to the example search term let's say search for hiking and yep get back some hiking podcasts cool remember this is using the podcast index which we are which is a rest api podcastindex.org so in in one of the previous episodes i think this is one of the first one we did yeah this was in the first one episode one we got the podcast search functionality working in our graphql api so there's a rest api let's get the docs rest api to search for podcast by search term and in our graphql api and here source if we take a look at the schema this is actually all implemented in cipher using apoc which i think is kind of fun so we construct the headers for the podcast index grabbing the authorization key that we've defined in a secrets file then we use apoc load json params to make a call to the podcast index rest api passing in our search term and then we return the results from the podcast index so i thought that was a fun use of the cipher directive in the neo4j graphical integration combined with some of the the cool functionality in cypher exposed through apoc to call another api so that made our server code a bit a bit simpler i think okay anyway oops playlists we wanted podcasts anyway so that's uh that's how that works behind the scenes so let's grab this podcast search query it says podcast query let's change this to podcast search query and change that here as well uh okay let's let's import some things here that we know we're going to need well we have another form that we're using to take in the search term so we're probably going to create a state variable for that let's bring that in because the user has to explicitly type something in and click a button we're actually going to not use use query so use query from apollo client that will execute a graphql query when the component loads so when the page loads in this case but we actually want to do it manually when the user clicks a button and for that we're going to use lazy query which is similar to mutation it gives us a function that we could call to then execute that query we will need to figure out if the user is authenticated because again since we want to encourage users to sign up for application so we don't want them we don't want to allow users to search for podcasts and subscribe to podcasts if they're not authenticated so we'll need to bring in our use auth hook our auth provider that we wrote a couple of episodes ago and then we'll need the sign in component if the user is not signed in we'll just show them the form and i think we know a few things we're going to want from chakra ui things like the form form control form label input button uh what are the other things we use container we like to use flex and we're showing up we're going to be showing a list of things here so let's bring in our v stack okay so currently this is this is what we're doing is well use query that's right we want to switch that to use lazy query and now this is going to give us a tuple so get and data we also have the loading and air state in here as well but i'll just skip that for now the is signed in function from our use hook and then let's go ahead and create a state variable for our search string so we'll get the variable and the function to update it set search string okay so now let's put this in a container instead of a div so that our nice theme styles are applied we don't need this h1 i don't think so just like we did before if they're not signed in then we will render the sign in component and if the user is signed in then we will render well we need to add a form and then a list of podcasts so if they are signed in let's wrap this in a div so this will be a form control let's call this podcast search and we'll give it a label search for podcasts let's look at the form in chakra for an example um okay so then i i think we'll we'll do a flex because again we're gonna similar to what we did with the playlist we're going to have the input and then we want the button right next to it so i like to use flex for flexbox and we'll have an input and when we start typing in this input we need to set the search string set the search string state variable to the value in the form field and we need a button this will be our search button and when we click the search button that is when we run the mutation get podcasts and we need to pass in the variables object which is going to be search term is so search term that's the graphql variable we defined up here and that is search string which is the value in the form field and then down here we so this is from our previous where we were executing a graphql query using the podcast query field this is podcast search so the results will be a bit different um but i think that that i think should work so we have the form the button when we click it and then we just render an unordered list showing the title let's try that so we need to sign in search for podcasts oh let's put some margin left on our button there we go so if i search for hiking podcasts there we go get back the title a bunch of hiking podcasts okay but we don't want to show just a just the title of podcast we want to show like the show art we want to give the name of the podcast the description of the podcast and show the categories of the podcast and then we want to have a button for the user to then subscribe to the podcast so let's create a new component so not in pages but in components since it won't be everything in pages maps to the next js filebase router so we want just a component let's call this podcast and so the podcast component similar to our episode component let's take a look at this our episode component this is a flexbox with lost our lost our authenticated state there let's sign in again so this is a flexbox with a rounded border then here this is a box shocker component with an image and then full width button below and then on the right here i think our our podcast component will be a bit simpler we'll just have like title description and then oh we do have the categories so for categories chakra has a i think it's called a tag yeah something like this like a a tag that we'll use to kind of inline the categories so the episode component i think will end up being pretty similar to the podcast component okay so the podcast well it takes a podcast object as props and that is we have it in here yeah so title itunes id description artwork and categories and then we said just like our just like our episode it's the outer component is a flexbox and then a and then a box which is kind of kind of just like a dev uh but just kind of like a container and let's just set and so this is going to be the thing on the left here with the image and the button is is one box let's set the width just fixed to 200 uh px i think we can get away with that because all podcast art is square and 200 i think looks looks okay on any device okay so that's the box and then we want within that box the image where so chakra has a specific image component set that's where the images come from comes from we'll import that all in a second the source for this is artwork and set a size for this of 200px and then below that we'll have a button and this is going to be the subscribe button so let's use another one of those add icons like here this this looks good and then the other part so then the part on the right that's going to have the title and the description and the categories that is also going to be a box and let's set a max width on that we don't we don't need these to take up the whole screen so we know our box on the left is going to be 200 px let's set a max width on this one to 300 should probably be enough and we'll have a heading that's going to be the title and then text component which has some nice topography styles for the description and then we got artwork we got title description oh categories oh and we said we're going to use this tag component to show the categories kind of like inline pills so for that we're going to use a stack so stack we said is good for showing like a list of things previously we used a v stack which is like for stacking things vertically but we can also if we pass the is inline prop we can do those horizontally all in line which is quite nice and so for this we're going to iterate over the category so categories is an array of strings so we'll map over this and just return a tag i guess we should give it a key it's just the name of the category um is that i think oh we need to import a bunch of things here we need to import what button flex box image stack text tag heading from shocker ui and we need our oh we need our ad icon add icon from chakra ui icons that's a second it's a different package and now in podcast search if we import our podcast component now instead of an unordered list we can change this to a vertical stack v stack let's spell that correctly v stack and then instead of a list item we're going to return podcast component so let's see if that works uh podcast does not contain a default exports oh do we not did we not export oh podcast export default podcast okay so here's the search so we were searching for hiking uh p is not defined in podcasts oh yeah we so when we were mapping we used v and v for value p for podcast let's use p for podcast i had to refresh so let me sign in again search for hiking podcasts okay that's so i see some issues uh let's see if we can clean this up so a few things to think about i guess first of all we wanted that that like rounded border right so i think if we set large for rounded that gives us um a large rounded border and then border width we can set and let's give this some margin and let's see our button so one thing is our button here we want that to be 100 width so the same width as the image and then i think so what we see here is this looks okay except in in like some cases where we have some really long titles and some really long descriptions oh and then if we have a lot of categories we kind of overlap so let's let's slice the categories i guess let's just take the first three of those so we won't overrun i guess that's not going to be perfect if we have some long category names but should be fine and then for the heading so we can specify one thing i really like about the typography things in chakra is we can specify number of lines which will truncate so for the title let's do two lines if we had yeah so here it truncates that if it's going to go more than two lines and then let's do something similar for the description maybe three lines make sense there yeah and i and i am zoomed in a bit so this this is larger than it actually is okay so that's that's getting there let's add some margin on this box there we go and i don't know we could add some margin to this box as well i don't know i kind of like having the image to the edge i don't know kind of whatever your preference is there but okay that that looks okay i think i'm i'm satisfied with that uh and then we need so this button this is the subscribe button which currently does not do anything so let's make that do something uh so we want when we click that we want to subscribe the user to this podcast so if we go back to graphql playground in the docs in our mutations we have subscribed to podcast as a mutation field and that takes itunes id so our mutation is going to look something like this podcast subscribe itunes that's it itunes id which is a non-nullable string subscribe to podcast itunes id i was not consistent on the capitalization there that's fine so i both i and e are capitalized in my variable but not in the argument that's fine so subscribe to podcast and then turn title itunes id i don't think we really need those values okay so now in our podcast component let's call this podcast subscribe subscribe to podcast and did we import oh no we'll want to import gql and use mutation from apollo client ludwig says thanks for the videos look at this one tomorrow yeah cool and and i'll post the code as soon as we're done here up to the github repo and i have been writing blog posts as well for these although i'm a little bit behind on that but if you look in the in the readme here's the the blog post that we wrote when we did authentication we wrote the auth provider and started using next.js so all these i'll drop a link here to my personal blog you can find all these write-ups on my personal blog but yeah the the repo is the good place to go just to find the catch-up cool so gql and use mutation we imported from apollo clients and then what we call the subscribe mutation i guess is what it will be and i'll return some data use mutation for the podcast subscribe mutation cool so now for our button where's our button this button it gets an on click handler that executes the subscribe mutation making sure to pass in for the variables the itunes id and that's the prop that's passed in up here but remember our inconsistent casing so i think it looks like that so let's test this so let's search for i don't know a news podcast um what sort of news podcast do we like um how about the daily i like that one the new york times daily podcast there we go so if we subscribe to that that should fire off the mutation and then that will also if we look at the our graphql api that is when we parse the podcast feed so if you look at our graphql schema so we looked at the podcast search let's look at the mutations for subscribe to podcast this is what we're calling so this is also implemented all in cypher so what this one does this is also i think a fun one it makes a call to the podcast index looking up the podcast by itunes id and then finds the user so the currently authenticated user and then in cypher there's this merge which is kind of like a absurd git or create so if the podcast doesn't exist in the database it creates it and then it uses the apoc load xml so apoc is the like standard library for cipher so it includes procedures and functions that add functionality to cipher and we saw apoc load json up above where we're making making use of that to call the podcast index rest api but now what we're doing here is we have the feed url for the podcast so podcasts are just an rss feed which is like an xml document that conforms to a certain specification so we can parse the part the podcast feed using this apoc load xml to actually parse out from that rss feed for each podcast the details and then that then adds it to the database so anyway so if that worked if we go to our episode feed we should see some for the daily cool so looks like we see a lot for the daily because uh there's a new one of those every day and the other podcasts we have aren't updated as frequently one thing we're also not doing that we need to add and maybe we'll do this next time is make sure that we are regularly updating and then parsing our feeds to grab new podcasts which currently we're only parsing the feed to add episodes when a user subscribes to it so we need kind of a background job running there to be parsing episodes uh non-stop um i was kind of waiting until we had deployed our application somewhere to so we had a database hosted somewhere in the cloud and we can keep that keep updating that in the background consistently probably doesn't make sense to have that running locally but maybe that would be a good uh episode for next time let me know in the chat or let me know on twitter uh if you i'll drop a link to my twitter user this is me um so pingme ping me on twitter uh if you have ideas for what we should do in the next episode because i think that now we have implemented what we wanted to for today so we have our playlist functionality so we can view playlists create new playlists we can add podcasts to playlists and and then view that playlist we have our podcast search functionality that we built so we can search for podcasts to subscribe to when we subscribe to them then we tested that it shows up in our podcast feed we can add them to playlists now if we go look at playlists they show up so i think we accomplished everything we wanted for today so maybe we will call it good for today and yeah let me know what we should do for the next live stream um i think maybe deploying the database somewhere in the cloud setting up to constantly update in the background and then i guess also need to deploy the front end of our application as well so maybe we'll do that next time unless anyone has any other ideas for uh what to dig into next time friendly reminder like we talked about uh at the beginning if you're interested in submitting a talk for nodes 2021 the call for papers is closing april 5th so be sure and that's the the neo4j online conference so be sure to submit before that deadline if you're interested and then also lou and i started a new podcast called graph stuff fm which is all about neo4j from a developer perspective so if that sounds interesting you can you can search that in your favorite podcast app to search for neo4j or graph stuff um or go to graphstuff.fm to find those uh and yeah and in the meantime let me know what you think would be interesting to dig into for our next episode we still have some some features we need for our grandcast podcast application but thanks for watching today and we'll see you next time cheers you
Subscribe To Will's Newsletter
Want to know when the next blog post or video is published? Subscribe now!