Let's Play With Realtime
with Jason Lengstorf
Join Jason to have some fun with realtime coding. Let's see what we can build in 90 minutes — and then let's all test it together!
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
Then we have Prince coming on. Always a great friend of the show. He's going to teach us how to use Blender. I've never used it. I've been advised I need to install it and make sure my computer can handle running Blender and OBS at the same time. So we'll see. But I think that's going to be really fun. 3D is something I'm always blown away when I see people doing it, and I've never actually done it myself. So excited to learn. Then we'll talk about visual page building with Plasmic, which is like a drag-and-drop UI builder. But they're convinced we can do this in a way that's like a legit production app. So I'm really excited about that. Lots of good stuff coming. Then Sunil is coming back on. One of my favorite people. He's at Cloud Flair. I'm at Netlify. We both have edge offerings. To me, I feel like this is the most exciting space in web development. So I just want to talk about what it is, why we're excited about it, what we think it unlocks. That's going to be a really good one. That's probably more of a discussion than a real code along. We might just take questions and talk. That's going to be really fun if you're interested in learning more about the edge. What echo? Hold up, sorry. One second. Is the echo gone? Check, check, check. Lots of echo. Sorry. Oh, no. Better, echo is good. Yeah, all right, all right. Echo is gone. Okay. Sorry about that. I had both my -- remember last time when I did a solo episode and my camera died halfway through and I had to switch to my Macbook Pro camera and there was general chaos? I apparently forgot to turn that off. Sorry, everyone. And what's up, friends? Also, I love that -- Doug, I don't know if you were going for a joke by writing like echo over and over again. But that's a good joke. I'm going to give it to you. It's a good joke. What's up, Ben? What's up, Tony? Seeing lots of familiar faces. Hello, hello, everyone. Asqyoo. That is you, Ben.
So let me talk through this kind of idea that I have. So what James and I were talking about is this idea of what makes streaming fun is the interactive element. When I'm streaming, you, as the chat, can give me ideas. We can modify what's happening in realtime. So streams, rather than being a presentational thing where I'm standing up here saying I'm going to do this, and if you're thinking there's a better way to do it, you have to just sit tight and send me an email afterward. Or do nothing and I never know there was a better idea. You're helping me co-author this stream. That's what I love about this live medium, the co-creation of it all.
Let me pull up James' picture, since I'm talking about him here. What is James' handle? So we were talking about this at Remix. We were both at Remix Conf then Render ATL, both of which were very good conferences. So let me also pull those up. No, I don't want the '23. I want the '22. So there's the recordings for Remix Conf. Then Render ATL was also wonderful. Lots of cool things going on there. I had a blast for lots of different reasons. But anyway, James was at both of these. We were talking about how do we make, like, conference presentations as fun as livestreaming. And I think the answer is you don't, right. A conference presentation is different from a livestream. We don't necessarily want full audience participation in a conference because these talks are like 15 minutes long. You don't have as much time to screw up and recover. You want to get to a point. You're trying to teach something, and you want to do that. But I do think there's room for more interactivity. I think there's room for more ways to be connected and to include the audience, both remotely and in the crowd.
So we were talking about what that could look like. We started thinking about realtime tech and what this could mean. So are you all familiar with this idea of focus groups for TV? So focus groups for TV is -- there's probably a lot of ways to do it. One way I've seen that I thought was really clever is people are sitting, and as they're watching a show, they've got this knob. In the middle is kind of neutral. As they're watching the show, if they start to feel good, they turn the knob to the right to indicate they're enjoying themselves. If they start to feel bad, they turn the knob to the left to indicate they're not enjoying themselves. The control -- or the way they use these focus groups is they basically look and say, oh, well, people really liked this part of the show. So that's a thing we should do. But everybody disliked this part of the show, so maybe we drop that. I think that's really, really interesting. Now, I don't necessarily think we want to run a focus group on our conference talks, but I do kind of like the idea of playing with that so that the audience could share their opinion in kind of a collective, passive way as the talk is going on. So as a hypothetical, let's say I'm giving a talk about hot dogs. As I'm starting this talk, I'm going to put up a slide that says something like a hot dog is my favorite kind of sandwich. If you in the audience have scanned this QR code, you'll have a second-screen experience that kind of shows you meta content about the presentation you're watching. You can do something like maybe I'll show two options. I'll say a hot dog is my favorite kind of sandwich. One is an angry face because I just called the hot dog a sandwich. And one is a thumbs-up that says you agree, hot dogs are a great sandwich. In the lower corner of the presentation, we could actually kind of see where the crowd sentiment is on that particular claim, right. So that, to me, is really interesting. It gives us this ability to now make things pretty interactive in what I would consider to be a pretty dang fun way. So thinking about that, how would we go about building that? So that's what I want to figure out today. And we're going to see how far we can get. I have absolutely not thought about this at all. I'm just kind of thinking about what this could be. I have a general concept in my head, and I'm going to do my best to make it work. So let's create a new folder. We're going to call this realtime talks. And let's get into it. I'm going to get init here.
In this, I'm going to need -- oh, James is up here because James and I were talking about this. We were talking about this realtime idea. So that's kind of where this whole thing started. We would need to add code. What's interesting is at some point I turned off the noise on my end. I think y'all can hear the sound effects, but I can't hear the sound effects. And I think they're super loud. So let me make that happen. Okay. So let's start by -- let's just kind of start here by thinking through what we want to do. I have -- I want to have two UIs to start, right. So, let's see. Should I use -- how much do I remember about Nx? This is going to be like two separate apps, and I need to be able to run them both. I kind of want to not have to manually configure all that. So let's maybe bring Nx up. Nx is one of the sponsors of the show. I have very much enjoyed working with their stuff when I've used it. So I'm going to go to this create Nx workspace. I know React the best, so let's start with React. So I'm going to copy one of these and get an application up and running in minutes. That's what I want. So can I do this? Then I'm going to install that. Work space name is going to be -- we'll call this like main talk. Oh, wait. No, I screwed this up. Let's try again. One more time. This time it's going to work. This one is going to be realtime talks. I think this is going to actually double my folders. So application name is going to be main talk. I'm going to put in just plain old CSS, I think. Use Nx cloud. I can't remember what this does, so I'm just going to say yes because it's free, and I like free things. So we're installing dependencies. Let's see. Yeah, yeah, Nx picked up Lerna. That's very, very cool. Because Lerna -- and for folks who don't know, it's one of the OG mono repo setups. They posted a thing that was like we're deprecating Lerna, like it's over. Then Nx stepped in and took over, which is interesting, because if you look at it, like you could look at Lerna and say that's a direct competitor to Nx. But I dig that. I like the spirit of open source where it's all about making the ecosystem healthier for people, not about forcing everyone to use your tool by eliminating all the other options. I didn't mean to punctuate that with like a sips tea moment, but I did. So let's open this up and take a look at what it does. All right. So realtime talks. I definitely did a thing I didn't want to do. So let me open up -- let's see. Let's open up the -- I just want to look into this folder. LS. Does it have a .git? It doesn't. Okay. So here's what I want to do. I'm going to open my finder and just fix this so it's not double nested. I want to go into my GitHub folder. Here it is. Here's realtime talks. And I'm going to take everything out of -- actually, you know what I'm going to do. I'm going to take this one out, and it's going to -- can't be replaced by an item it contains. Boo. I can get rid of this parent. Am I still in the same place? Yes. So this now should be right. I'm going to get init here. It's already there, okay. There we go. All right. I did something weird by changing the system while I was in that folder and all that good stuff I did. All right. So now that I've got this, I'm going to close and reopen this so all these aren't grayed out. Oh, did it pick it up already? I don't think it did. I'm opening it again. All right.
So now we've got our apps, right. So here is our main talk app. Then to run these, if I remember correctly, I have to do something like -- I don't need to generate it. I want to run it. Nx serve my app. Okay. So I do Nx serve main talk. Do I have to install something? I thought I had this. Let's go with npm install Nx. Okay. So now we've got local host 4200. If I come out here, here is our main talk. Okay. So we've got that one. And I want to do something like let's just do some real basic stuff. I'm going to go into this app. We have our main.tsx. That's an app. App is here. All right. So there's our styles. So I'm going to drop out this Nx welcome because I don't need it. Because we're building out something different. So I'm going to delete this one. All right. Then I'm going to set up -- let's do -- let's see. How would we set up a slide? I want a full-width, full-height slide. So the way we're going to do that is we are going to go into our module, and we're going to say there's a slide here, and I want this to be a width of 100 viewport width units and a height of 100 viewport height units. Then a class name of styles slide. We'll put something inside of it. Fragments should contain more than one child, otherwise there's no need -- okay, cool. I can fix that. Now what do you want? Slide comes from an index signature. So it should be accessed with -- fine, fine. So we'll take this out here. Then we'll do like a -- let's just make this live, all right. Hot dogs are my favorite sandwich. Then we'll do a span aria label, right. It would be hot dog. Then you put in the -- somebody tell me if I'm doing this wrong. I'm trying to remember how to make an accessible emoji off the top of my head. I think this is -- nope, that's not right. It wants role image. Got close. Operation not permitted, you don't have a medical permit. (Laughter)
All right. So let's give it a color so we can see what's going on. We'll do a background color of -- let's go with something that's not going to blow our eyes out. That seems like a good one. Let's do that. So here's this. Now we've got the issue that I was worried we would have, which is that we have a default margin. So we're going to say HTML and body are going to have a margin of zero and a padding of zero. Then we'll say like HTML is going to have -- that does not work anymore. We'll just let Co-Pilot do the rest. How are we looking out here? Closer, closer. Okay. So then what I want is I want this to be box sizing, border box. And why don't we get rid of margins in general. Margins are not what we want. We'll set those manually. So then, because it's a slide, I want these to be -- let's vertically center everything. So I'm going to display flex. I'm going to justify content center. We're going to have to flex direction column because we don't want the heading and the hot dog to be together. Then line items center. What that should give us -- oh, all right. I want the ability to make that text bigger. So I'm going to say -- we'll just give it something like big text. Then I'm going to say font size. Wow, look at you. Don't need any of that, though. We'll give this a class name of styles. Boom. Look at this go. I'm really happy about this. This is doing really well. This is a risky looking link Tony sent without vetting it at all. Yeah, well, I mean we knew we'd get here eventually, right? (Laughter) Oh, wow. Look at this. So this is -- okay, that's not -- I thought that was a poll. I was like, oh, we're building that. Okay.
So we've got this. Then the thing that I'm looking for here is how do we get some kind of a sentiment analysis down at the bottom. I think the way that I want to do that is with -- let's see. How can we do it? If we do something in the center, right, so put like -- we can probably just start with a circle so we don't have to think through the Ux of it. Start with a circle in the center, then we could have bars that go to the left and right. That would indicate like approval or disapproval of a statement. So we could have -- you know, looking at this section here, if we have a center point, and if people like it, this bar would grow. If they don't like it, this bar would grow. Ideally, both would be growing at the same general speed, but it would just kind of show. An important thing for me is we're not going for, like, direct polling. I don't necessarily want this to be a do you use TypeScript, yes or no, and people would answer yes or no and we see the poll result. It could be used for that, and I think that would be really fun. But apps exist that do that sort of thing. What I'm looking for is more of, like, a passive visualization that makes things fun and chaotic. In a way that's not super distracting. So I don't necessarily think I would implement the boop drop or the Corgi stampede on my slides. But I do kind of like the idea of reserving a portion of the slide for some kind of visualization that shows what the audience is feeling or thinking about the slide as it goes. Make the disapproval go up if you yell at the page. (Laughter) Come on, Ben. That's hurtful. But yeah, you're not wrong.
Okay. So we've got our slide. We've got our slide, and then what we need inside of our slide is we need -- tug-of-war is actually a fun idea. Let's see if we can get this mocked up and see what we can make it do. Let's go with -- we'll just go with something that's kind of obvious. We'll call it responses. Then in the responses, we will need -- how do we want to do this? We can do this as -- so we also need to think about how this will be accessible. We want it to visually be there. I know this is a slide deck, and it's very unlikely that somebody would be looking at my slide deck using accessibility tools while I'm giving the talk. But it's a good habit to think through how would this work. Later, maybe this gets embedded in a web page and somebody can be -- you know, it's like for a live event. We're all doing a watch party, and then you do want to be thinking about how assistive tech would work. So maybe we do something like how the audience is feeling. Then we have -- should I use the meter element? I probably should use the meter element.
So we have a meter. The meter gives us a value. Okay. This probably looks right because then we've got a min/max. This is fascinating. Low, minimum, optimum. Cool. I don't know if we're going to get to any of that today, but what we can do is we can pull this to this side, pull this to this side, hide that side bar, and let's go with -- can we just throw these in? We'll call this good. We'll say meter ID good. We'll give it a min of zero, a max of 100. And let's start them both with a value of 50. Then we can do the same thing for bad, right. Then if we take that and we put it on the screen, it looks like -- where's my thing? Here. Okay. So we're pretty -- you know, this isn't bad. Honestly, as is, it could kind of work here. So this is very, very cool. Can we flip the meter element to be right to left? That would be very cool. So let's try it. Let's see. Let's see what we can pull off here. So I'm going to do a class name equals -- and we're going to have a couple of these. First one is going to be styles. We'll just call it meter. Then the next one is going to be for the styles. We'll call it, like, meter good and meter bad. I kind of hate that, but it's okay. We're not going for beautiful, production-ready code. We're prototyping today. So let's get in here and look at our meters. So we've got meter, and I want to do something like -- what are the properties you can even style in a meter? Do they have styling guides in here? Min/max, cool. Yeah, how do you do -- CSS tricks. That feels like the right thing to do. Let's get in here and look. We've got attributes. Where are the styles? Okay. So we can just set a width and height. Let's start there. We'll go with a width of -- let's see. We want our centered circle thing to be a certain size. So we can do like a calc of 50 minus 6 rems, so 3 rems on each side. Feeling good about that. I also need to get the visually hidden class. Well, actually, no, I don't. We're going to need to show what this means, right. So maybe indeed, we want to do another one of these buddies. Instead of text, we will put in an emoji. For good, we'll do the yum. No, that's not right. This is going to be like yum face. Then out here, I need some visually hidden text. We can say span class, visually hidden. I'm going to make that a global class because we want to use that somewhere else. Then we'll say feeling good. Then we can do the same thing here. I'm just going to look at chat to make sure I'm not doing anything that everybody is very upset about. Everybody seems happy. Clearly I am a genius. Okay. So this one is going to be angry face. And feeling bad. Good, all right. Let's get to into our styles, and then I need to create that visually hidden CSS. There's a good one in here. Let's just grab this, and we'll put it here and change it to visually hidden. Now that I've done that directly, there they go. They're gone.
All right. So, now we want to show these where feeling bad should be on the left, good should be on the right. So let's swap the order. Whoops, I screwed that up. Okay. Then I want to see if we can flip the right to left of the meter bad. That's not it. I guess we could do something really -- transform scale X minus one. There we go. So that'll do it. Should there just be one meter with 50% being neutral? I mean, you're probably right. Hmmm. What do you think, chat? Should we make it one meter, and it's like it is a tug-of-war? Yes, one meter. All right, we'll do it. So we can get rid of this one. We'll have to change this out a little bit. Now it's going to be not a label anymore but more of just a paragraph. Then we don't need that anymore. Let's see, how is this going to work? We'll do this one outside. Then we've got our label, but we'll make the label visually hidden entirely. Then we don't need that span anymore. Okay. So that all seems okay. And I want to swap this out somehow. Let's just go with a div class name, styles, meter container. When in doubt, wrap it in a div. That's right, that's right. That's what all the advocates say, right? When in doubt, wrap it in a div. Then in a meter container, we can display flex, and we'll do a justify content. I call this the Dave Matthews because it's the space between. Yeah, there we go. This is looking pretty good here. Then I also don't need to flip this meter anymore because we actually do want it to kind of go this way. So then we probably want to use the good and bad, right, where the meter has a -- you have like the thresholds. High/low. So high is where we want it to be happy, and low is where we want it to be sad. So we'll say high is going to be, like, 55, right. We'll make it pretty easy to see whether people are feeling this or not. So we've got a high and a low. Then if we come back out here -- what did I do wrong? Type stream is not assignable to type number. Nobody is trying to make you a number, my dude. I guess we deleted that style, didn't we. That's what happened. That feels like it should recover. Failed to compile. Oh, these are supposed to be -- that's very annoying. Okay, all right. That's good.
Let's change the value to 40. Let's change it to 60. Oh, I probably need to change it to, like -- hmmm. Okay. So let's style it. Should it be a meter or a slider? Don't know. Don't know what the right thing to do is. I guess what we could say is this is a meter indicating the percent of people who approve of this thing. Let's go with a background color. So we have a background color, box shadows. You can do linear gradients. Okay, that's kind of fun. What if I just want to change what happens when it's high or low. Optimum, suboptimum. Sub-suboptimum? What? Vault falls inside the low/high range. Outside the low/high range. Value in opposite zones. What? Value is less than low, is less than high, is less than optimum? What does that even mean? Also, what does meter junk mean? Internet Explorer, oh, boy. This is old, isn't it? Maybe I need an updated thingy. This is from 2011. Better solution in 2019. Oh, you do still have to do the thing. Fine. Maybe a slider, one slide is red -- yeah, you're making good arguments, chat. Let's go to the slider element. Let's get ourselves a range. And we want to do something -- so we'll keep the min/max, change it to a type range. And we get rid of the high and low because we don't need those anymore. Then we'll need to update that class name. But this is -- okay, that feels like it's okay. I'm going to put this on another line so we have a little easier time editing. All right. So we've got a range here. We're going to call this a sentiment. Current sentiment. We'll probably have to figure out some ways to, like -- wait a minute. Can we do attribute selectors? Let's try. Okay. So I'm going to do -- I'm just going to do a really basic experiment. I'm going to put a div down here, and we're going to call this -- no, I'm going to do it within the meter itself. So we're going to change the style name to sentiment as well. Then probably the same here. Just so that we -- all right. Now we've kind of got a thing. If I set the color to red -- that's not it. If we set the background to red -- that's not it either. How do we style this? Show me styles. Examples, styling, hash marks and labels. Oh, that's cool. Oh, this is also very cool. Look at that. Right? List is tick marks. I like that. That's cool.
So then we've got vertical range controls. Requires adding CSS. That's fine. But what I really want -- appearance, slider vertical, yeah. But what I really want is colors and stuff. Styling the range element. That's what I want. Here we go. Back to CSS tricks because you always go back to CSS tricks. Inspect element. Weird. We're getting into stuff. Structure on the edge is much more complex. Why are they all like this? We're not just going to get, like, plain old styles, are we? Initial styles. What if I just want to set the color, though? There's a lot in this article, and I feel like it's skipping the pieces I care about. No shade on the author. What is happening? In-line style, no. Clearly you can't just change the color on this. Inspect, okay. Cursor color. Internal light/dark. Input. So it says there are colors, but it's definitely not using any of them. Color. What if we just give it a height? Does that break it? We're going to have to custom style this if we want this to do anything other than what it's doing now, which is -- oh! Webneat. Perfect. This is what I was looking for. Thank you. We want the accent color. Didn't know that was a property. I want to see if I can do sentiment value equal to 45. There's no way this is going to work, right? There's no way this is going to work. And we're going to do if it is greater than or equal to 55, we'll do green. Okay. Then otherwise, it's going to be -- and I can't set that because I did something. Don't know what. But let's -- that should make it green. Clearly that didn't actually do what I wanted. Let's see. Can you get CSS use input value in calc? Value equals United States. That's fine, but that's not quite what I'm after. So you can't do math. That's unfortunate. You need default value. Oh, default value. That's a good call. So default value. So we'll have a default value of 50. Now we can actually move it. But it does not change the way I want it to change because this is not real. But what if -- let's see. Hmmm, would this work, if we make the min one and this 99? We can get clever. Oh, it won't work because then we would have the one, two, three stuff break. I was going to get real clever. Oh, just kidding, we can do it. We can do 10 and 99.
Then if it starts with this one -- if it starts with one or -- you ready for these hacks -- two, three, four, right? Two, three, four. Then it's low. And if it starts with six, seven, eight, nine, it's green. And that should have worked and it didn't. Did I get that wrong? Exactly or beginning with. Do I need one of these instead? Boo. Okay. Wait a minute. Input in range, range specified. What is that? Wait, how does that work, though? Values between one and ten are valid. Your value is out of range. Oh, that's close. That's close but not quite what we're after. We're trying to get, like, different colors. Now, all of these are in range. You know what, though? I'm definitely hyperfocused on the wrong thing here, right. We should be trying to make any of this realtime because we've got, what, 40 minutes left, and we haven't even gotten close to doing any of that. So, yeah. This is going to be fine. What I want to be able to do is update this value, and I want to be able to do that with realtime. So let's set up our second thingy. What I want to do is make that bigger again. We're going to go to docs. I want to create a new UI. And I want to make a thing, generator. Work space generators. I don't want a workspace. I want a new thing. I want a new application. No, that's not it. Creating libraries, applications. I want to create an application. That's not it. So you can create a lib. How do I create an app? So I create a new workspace. That part makes sense. Then that created an app, but I want to create another app. Hmmm. Maybe I just need to do one of these, look in here, see if it'll show me what I did. Oh, that's -- is it in here? First time using Nx. Well, I get how to do that part. How do I create another one, though? Nx, generate. Okay. Is that the thing I needed? React. Generating, managing React applications. So that's what I want. We're going to do second screen. I don't need React Router. Okay. So now if I do -- what was the command before? Nx serve main talk. Now I can do second screen. Now if I come out here, now we're on second screen. Okay. So this is all making sense. We can make this work. So out here what I want is if we close this one down, we can see second screen. So yeah, now that I remember what the commands are, I think this mono repo stuff is dope. So in here, we get rid of this. We can make this into a thingy, this into a thingy. We'll say how do you feel about this nonsense? Actually, probably this needs to be like a form. That'll have a button of ID, good. Then that'll need to have this one. Then we need one more. Okay. So we have our buttons. I feel good our bad about that. Now I want to get a little bit of something going. So I'm try to think, what should we use for realtime? I'm going to use Ably because I think it does what I need and has a free tier. Start with a free account. Let's double check what that free account allows. 100 peak connections. We have 65 people watching. That'll work. Let's get in here. Sign up with GitHub. I already have an account. Great. Okay. So I'm going to create a new app, and we're going to call this realtime talks. I'm going to say yes. Supabase? Oh, it has the auth, too, right? Maybe I do want to use Supabase. It would be nice if people logged in with their Twitter or GitHub or something. And that'll give us realtime. Yeah, let's do it. So I'm going to make a new project. We're going to put it here. I'm going to call it realtime talks. Database password. Did it generate one? No. Okay. So there is our password. Good. I'm near California, so let's do that. Free plan. Getting my project. Let me store this password somewhere before I lose it. Okay. Project API keys, it didn't show them. Thank you very much for not doing that. Okay. So what I need to do is get in here and say we need -- we want auth to start. So let's do authentication and use GitHub because I feel like that's probably the thing most people will most likely have. So I need to create and configure an OAuth app with GitHub. We're going to squeak down to the wire getting this done.
So let's go to here, settings. I've got to go down to developers. And I'm going to have to create a new GitHub app. Wait, GitHub OAuth app. So we're going to create a new one. We'll call this realtime talks. It's going to have a homepage URL of something. Let's just assume that we're going to call this realtime-talks-lwj Netlify app. We're going to have to change -- I bet we have to change this later. I'm going to just say we don't need the device flow. So I'm going to register it. I have a client ID. Okay. So let's go over here, add to Supabase project. I don't want that. I just want to set one up. Settings? Set URL. Good, good, good. Email auth, phone auth, GitHub. All right. Client ID. Okay. Then I need to send my secrets. So I'm going to come over here and generate one. And this is my client secret. Pretty sure it's going to -- all right. Save. And these were going to be local host 4200, I think. Probably need one more of those. So let's do the realtime-talks-lwj.netlify.app because that's probably what we want to do. Let's save all this. Now we can come back over here. Now we need to add the log-in code to your Supabase JS. Oh, it's actually in here already. So click on the settings at the bottom left side of the side bar. Settings, bottom left side of the side bar. Click on API in the list. Settings, settings, API. Under config URL. Am I looking at this? Project URL, querying and managing. It's this one here, I assume. Settings, API, API URL. Restful end point. That's got to be it. Then I add /V1/callback. So I have to go back to GitHub, which is here now that the key is not being shown. So then I can go here. Our callback URL is going to be this one, and I need to add more stuff to it. So let's add this. All right. Then I'm going to update. Now what do we got? We got register new OAuth application. Where? Generate a new ID. We did that.
Use state, any. Get away. Can you at least not explode now? So now it says logging in, and I have an infinite redirect. So I've done something wrong. Let's maybe not call this on the first call here. I should probably make that a button. I'm going to need to be able to call it. We're not going to do the use effect. We are, instead, going to have a button that says log in. Out of time yet? So close. Please don't yell at me for hacking this together. I just really want to see something work. So we have a sign-in button. Now, if I sign in, this should get my -- console.log. Then user session error. That should show us something. So let's go to console, and then let's sign in. I'm going to authorize. Here the user session was null. We didn't get any of those details. Which means I need to -- it means I need to read more of the documentation is what I'm going to assume. So let's get here. Where was the quick start with React? Quick start, React. Okay. Just show me some code. Initialize react app, set up a log-in component. Okay. So here's our log-in component. This is the magic link, though. I don't want the magic link. Handle log-in, which will set loading. It awaits for the Supabase auth. And then it says set loading false. But I don't understand why it would -- on submit handle log-in. Right, that's what I want. Sending magic link. Does it take you somewhere if you have a thing? So this is just checking the auth. So Supabase.auth.user. Okay. So maybe I'll just do, like, await Supabase -- oh, you got to do all this stuff too. That's great. Oh, man. So I'm going to have to copy/paste a bunch of stuff. I really just want to click a button and get the thing, though. That's what I'm after here. Then this should theoretically one and get me my user. So I'm going to sign in. And then I want to -- after I've signed in, I want to do like a use effect that will look for my user. Then I should be able to do something like async function, load user. Then I should be able to do like user equals -- and what was the thing? Supabase auth user. But where is this user used? Const user. Yeah, it keeps saying const user, and then it doesn't use the user. There's a session user. Where did the session come from? User, here's my user. We at least get a user ID. All right. So let's try that. Let's see if we can get something. We will load user and stop the infinite redirect that way, I hope. So over here, load. Now it says I have a user. Okay, that's good. I gotten a email. What else is in here? Email identities? Any of these -- Avatar, URL, full name. Okay, so we're getting some stuff. I can use my user, and when we set that -- so I don't know if I actually need this piece. User, set user. Then we'll go use state with nothing. Just leave it undefined. Then don't need to do that because that comes out of Supabase, not out of React. Then when I get this, I can set user to be user. And you're going to yell at me because user or null is not -- now I hit React with a stick. Good. Then I can do an if there's not a user, otherwise we'll show our form. Good, now we have a thing. So with our five remaining minutes, let's see if we can get this stuff to show up. So I want then a database, table editor. Let's create a new table. We'll call this sentiment. I mean, we're just doing basic stuff here. We'll just do a value. The value is going to be an enum. Do we get that? I love this automatic refreshing whenever I scroll down the page. I'm just going to go with text because that's thing I can scroll to. So we'll do a value of good or bad. So let's save. And now we've got this. Okay. So if I want to insert something into that row, go to here maybe. So let's get out of auth. I instead want to get into databases. And I want to create data. So I'm going to insert, right. So we'll do something like form on submit, and you will do create vote. And that is going to be an async function. Create vote. And that's going to need the event. Then we'll do an event, prevent default. Down here, one of these again. It's not just implicitly. It's intentionally. How do I make you go away? Then down here, I want to do, like -- oh, can I tell which button was clicked? Is that a thing?
Oh, hey, friends. Thank you, purplelf, for the raid. Appreciate the beard love. We're actually just coming up to the end of this stream, and it's looking like I'm not going to get to any of the stuff I wanted to do. As usual, I spent the entire stream fiddling with CSS. So let's get -- all right, so I have the ability to insert some data. So let's hard code some data.
So my table is called sentiment, and I want to put a value. The value is -- I'm just going to hard code some stuff for a second. Then I need a user ID as well. Crap. And that's going to have to be user ID, right? That's what we were storing, if I look over here. User.ID, yes. So we can use that. When I come out to my table here, can I edit the table? Yes, I'm going to add a column. We're going to say -- can I just make this like a user ID? That's nice. Save. Got to name it. Okay. So that's linked. When I go to drop in my user ID, that's going to be user.ID. You are not going to let me do this, are you? Get mad at me all you want, TypeScript. I do what I want. So then down in here, I'm going to console log data error. Let's give this a rip and see if we can get some data into the database. So I'm logged in, right. Now I'm going to say I agree that a sandwich -- we've got data. It says it created -- oh, good, good, good. All right. Let's go back in here and look. And we've got rows. Hey! All right. So that's not bad. Okay. So then, let's think about how we'd get this same thing if we wanted to pull this. I want to on subscribe. So in my other setup, what I want then, is I want to get my -- oh, I did a mess up here, didn't I. Let me get one of these. Then I'm going to get one of these, copy that. I'm going to come over here and stick this up at the top. And we've got a Supabase setup, right. And now down here, I want to use this subscription. We'll set this up in use effect. And that use effect will do something like this. Can I just hit that? Like, does that just work? Maybe. No. Subscribe, change. This needs cleaned up. Like, we're not doing anything that would, like, delete this. How do you tear down the subscription? Listening to inserts. That's really what I want. Insert, right. So what I want is for my app -- and I'm just going to open this up in another -- we're going to do Nx run. Nx serve second screen. So I want to Nx serve main. And I have a duplicate port, which means I need to change my port. That's going to be in here probably, somewhere, maybe. Project JSON. Come on. Don't let that be the thing. Okay. We're just going to stop the other one. And we'll insert the row manually to see if we can get -- here's 4200. So this is running. Now if we take this one over here -- how many minutes we got? We have exactly zero minutes. So let's try this once, and if it doesn't work, we will, I don't know, do nothing, I guess. I'm going to click this button to insert a row. And that's going to be automatically generated. The value is going to be bad. And the user ID is going to be my user ID. Please enter a value in the user ID field first. Crap, come on. Okay. Give me a user ID. I just want to copy/paste it. Thank you. Cancel. Open this up. Bad, user ID. We should see a console log right now. And we didn't. Because there's an error because it tried to connect to -- yeah, I did something wrong. Well, so we almost got realtime. We got really, really close to accomplishing something today. I just want you all to bask in the glory of, you know, sometimes you get right up to the finish line and you just trip over your own feet, fall face first in the dirt, and watch somebody else beat you to the end. That's what happened to us today. I was defeated by CSS. Well, I wasn't defeated by CSS. I was defeated by myself.
But that was a lot of fun. I think we will probably need to set up a follow-up to see if we can get this the rest of the way because I think we got a lot of promise here. There's a lot going on. And this thing is very close to being usable. So if we get a little bit further, we would be able to get that realtime running so that every time a new vote is made, it would be caught here, and we'd be able to use that to increment or decrement the meter value, which would let us move that more toward the happy face or the angry face. So I think we can probably do this in one more session. But this one is over. So we're going to do one more shout out to the schedule, make sure you head to the schedule and add this so you can go and learn how all of this good stuff that's coming up works. Then you can also, you know, follow on Twitch, subscribe on Twitch, follow on YouTube. That's another good way to make things happen. This episode, like every episode, has been live captioned. We've had Rachel with us today from White Coat Captioning, if I can bring up my homepage. Oh, man, I'm so over time, we've lost the captioning. Sorry. Yeah, so this was sponsored by Netlify, Nx, and Backlight, all of whom are making the show more accessible to more people. Thank you for hanging out with me today. We're going to find somebody to raid. We'll see you all next time.