Weekend Project Weekend: Saturday build

Sahil Lavingia builds a web product called Verification Letters from scratch in one live session. He sets up a Rails app with Supabase, deploys to Heroku, and wires a Stripe payment flow, shipping a working product on a custom domain in under an hour.
Chapters
Awesome. Meeting is now streaming on YouTube. Let's try and see where it's at. Presumably it would be in my— boom. Awesome.
Looks like it's working.
Let me click through and I'm listening to myself talk. Is that right? Awesome. Yep. Awesome. Cool. Cool.
Sorry for the delay. 5 minutes. Not too bad.
Let me just post it in the Discord and post it, uh, on Twitter.
Now we'll be back.
Hopefully it would be— let me close this and let me use the chat.
Cool. One. Yeah, I think that should be everything that I need to do to get started.
So Let me share my screen and let's get started.
And apologies for the thumbnail, I guess that's my YouTube cover. So everyone should see what I'm seeing. At some point I will, once my laptop has enough battery, I'll be able to connect my, um, my iPad, but everyone should see my screen.
Uh, someone just type in the general channel that they can see my screen and then I will Get moving. Come on. Come on.
Oh no, wait.
I forgot to— I forgot to— it's kind of annoying, this image, by the way. Oh, there's my mom. Okay. My mom can see. Cool.
Let me just tweet and then I'll start building. Not too much more to do.
Did I spell continuing right?
Oh no.
Yes.
Sweet.
Cool. Let's get started. I will close this, but everyone should still be able to see me and I am streaming live. So awesome. So the first thing that I mentioned kind of last time, um, oh yeah, by the way, I guess there are probably people who are, have not, maybe are like catching up or this is kind of their first interaction with this thing. Um, and so there's a really great thread. I'll put this all in the Discord. So I kind of highly recommend that you join the Discord. Um, cause that's kind of a good kind of culmination of all these sorts of things.
Um, But I will close this too.
But yeah, it's a great thread that kind of sums up kind of what we talked about. And that kickoff video is live on YouTube now. So this is kind of what we're talking about over the course of this weekend. And we're now at the build, the build kind of build part of the thing. So the to-do list from yesterday, you know, idea, co-founder of Crewmate, who is my mom. So I'm gonna kind of hand off the business to her hopefully tomorrow or day after tomorrow. I designed the prototype in, in Figma, which everyone can see. And if you haven't seen it, you can also go to Discord and find that. And then now we're building, building the product. And the product is really a website with two functions, right? There's the sort of investor submission form and then there's the dashboard. And there's some other stuff, like I have to figure out the email receipts and things like that. But Nothing too crazy. It's a pretty simple, simple idea. And normally when I have, when I do these little Notion memos for all my projects, I normally like to put the Figma embed in there just to kind of have it. So let me just do that to mimic what I do in real life. Yeah.
So normally I just, I do something like what, or prototype, you know, something like that. And then I kind of resize it to have enough context so anyone looking at this can kind of get a sense and they can also click through and play with it and do all that fun stuff. So, and I'll be using the Figma file a lot, you know, cuz that's, that's kind of what, when I start writing code where I'm gonna be pulling it from.
So yesterday the only thing I did in terms of building is I created this repo that has really nothing in it.
And you can see that because when I open the repo, and again, I'm not the best engineer on planet Earth.
That's not what I'm trying to communicate here. So I'm sure engineers watching will tell me that there's all sorts of shortcuts that exist, but I don't write enough code to be honest, to like build up that, that muscle memory. But, uh, Yeah. So it has the .gitignore and the README basically were from, from GitHub. And, you know, normally I like to like fill these out with things, but there's nothing here. Nothing, nothing kind of exists. So let's make something, let's make something exist. There is the website. And normally what I like to do is I like to just have the website like set up so I can always send people to something and there's something, something there, you know? So let me think about what is the easiest. I think the easiest, the absolute easiest thing, and we'll change this, but let's just do it to show people. So use a product called, is it called super.so? Yep. And this is a really cool thing that basically allows you to host your sites on Notion. So let's go through it and I'm actually gonna create a new, actually, you know what I'm gonna do first? I'm gonna do this all under the domain for verification letters. Um, so that way it's much easier to hand off everything, um, instead of having it all tied to my personal account.
So let me just do that, and I honestly haven't done this in years, so we'll find out how to do it together. All right, verification letters. I guess this is what I want. Get workspace. Cool. Just make that high for now. That makes sense to me.
I have to pay money for this. I'll pay whatever the lowest is. What do I lose?
Some storage, I guess. Whatever. That's fine.
Payment. Hopefully my payment information doesn't stream live to everybody right now.
Cool.
That was easy. So now I have an email, I guess.
Awesome.
And that way I can use my—
oh, it takes a minute, I guess.
Um, but let's test it out. So let's go to my email. Sorry if I dox anyone who emailed me recently.
And let's do verificationletters.com. See if that shows back up to me. Cool, that looks like it's set up. Normally, you're supposed to get an email when things are ready. So let's see when that shows up. Nope, that's not what I want. Let me archive all these emails so no one reads them. Yeah, lots of emails this morning. Oh, no, I don't want to do that. Let me untap that Reply Later to all this.
Cool.
Oh, I saw it. Where did it go? No, I didn't see it. I thought I saw something. Nope.
Well, I didn't get a failed delivery, so that's nice.
Why is this not working? Or what happens if I just use it? Hi@verificationletters.com.
And generally I use 1Password.
Let's generate password.
And yes, I know that this means people can use it, so please don't. And I'll go through and change all the passwords after this.
An error occurred. That's not helpful. I assume my password was incorrect. Bug report for Super.
One great thing, by the way, of building businesses, like even small tiny ones, is you realize how, you know, how much work there is to be done for these products to be good. So I'm just gonna use this.
For now just to have something. Actually, you know what I can do? I'll create another one and use that.
And this might feel kind of stupid and that's fine.
Computer's slow, so let me close these things.
Cool. So now I have this URL.
I'll share it to the web and I'll copy the link and then boom, put it here.
I started by the way at 10:10. Normally I'm faster. I'm kind of starting almost entirely from scratch and now I have a URL that I can send someone.
Boom.
I send you this, you now see this. And if you wanted to build kind of a no-code version, you could use a Google Form. You could just say, fill out this form and then you could use Zapier to like send the Google Form submissions. To Airtable, and then you could build a dashboard in Airtable. You could do all that stuff basically using no-code, but I like code, so I'm gonna do it with code.
And just cuz I like domains, even though this costs some money, uh, I actually don't know if this is gonna work. Actually, no, I'm not gonna type this live.
Um, so yeah, let's go without the domain. Um, but, uh, yeah, that's just an example of it working.
So the next thing I'm gonna just go to Heroku.
Heroku's gonna be the platform that I use.
I'm gonna use Heroku and Supabase and Rails. Let's see what shows up.
By the way, this is what being an engineer is like.
Just trying stuff out. And I'll open the chat on my phone so I can see it and see what questions folks have.
Cool. Oh, let me stop sharing my screen so the database doesn't get Screwed.
And I'll use this. How do I do autofill?
Don't worry, I'm just setting up an account for, uh, Supabase.
Nothing too crazy. I just don't want my passwords to get leaked, you know.
Create a new Supabase account. You can see the business I'm building, by the way, on, uh, in the Discord.
There's information about it. Cool. So that is fun.
And that actually provisions a database and API endpoint.
So that's pretty awesome. Actually, create a new project connection strings. Log into my—
now I'm just going into my Heroku account.
I'm actually going to create a new Heroku account. And use hi@verificationletters.com as the— Ruby, probably. I'm not a robot. Okay, now I have to verify my emails, which means that I have to set that up.
Oh, I got it.
The administrator has created a new account for you.
Awesome.
My verification letters and my temporary password.
Boom, I'm in.
Create account.
I'm a, oh, big Sahil fan. I'm coding basically all of it this weekend is the goal. I've now changed the password to something else using 1Password. And I love 1Password, makes it super easy to just like share passwords with folks. It's gonna be great when I hand it off to my mama. Um, and just to share my screen again, I'll probably just do this back and forth. I now have my email set up, hi@verificationletters.com, which is awesome.
Boom, it works.
I already got an email.
All right, let's verify Heroku. Oh, do the same thing with the password. Stop share. Um, suggest password. Hi verification. Set password and login.
And here to proceed.
And I'll share my screen again.
And this is where Heroku took me. Look at the state of software. You know, you think we're in the future. It's so bad. I like get literally got redirected to a page not found link after logging in.
Like, what the hell?
It's miserable. Okay.
Am I domiciled in Italy? That is, I'm interested in why they're asking me that specifically.
Uh, but no. Create new app, verification letters, letters. I don't know what add to pipeline means.
Um, ooh, let's connect it to GitHub.
Ooh. And let's use this too. That seems fun. But first let's connect to GitHub cuz I know that's That will be easier. So I've connected to GitHub and now the repository name, I believe, is just verification letters. So let's connect.
And then what I'll do is I'll make it so that the branch automatically deploys.
So every time we push to it, deploys will happen. Awesome.
And then let me spin up a super simple Rails app on Heroku.
Oh, we gotta log in. If you don't like doing tutorials to learn, by the way, you're not gonna like doing your actual work because it turns out your actual work is also just going back through, like going back through the tutorials. Uh, cuz you never remember this stuff cuz like how frequently do you have to do any of this?
You know?
GitHub. Yeah. Farhan asks, can you spend a little bit of time on, uh, GitHub, Supabase, and Heroku? So Heroku is the server, kind of like the hosting provider. Um, so, you know, basically you can think of that as like the server that, you know, in the traditional world. Um, and then GitHub is where the code is actually hosted. So I push code from my local computer to GitHub, GitHub will automatically, Heroku will kind of, you know, watch that change, those, that for changes. And then when there are changes, will automatically deploy to kind of the server. And then, you know, the DNS from Google Domains, I'll point to Heroku. And then Supabase is the, is the database I think is what I'll use it for. But honestly, I don't know, like you're asking me a question I don't really even know the answer to, to be honest. Like I would just Google. Like just Google GitHub Supabase Heroku. The answers are there, just kind of like what I'm doing.
Awesome. So that looks like it worked. I have a lot of tabs. All right, let's do that. I don't even know what no document means, but trust. Trust the tutorial.
By the way, follow along if you want.
I'm using a MacBook Pro, 13-inch, I think, or 13.1 or whatever the number is. Hopefully that's exact enough for you.
And I will create a new thing called verification letters. This might do something annoying, which I don't like, which is it might create a folder called verification letters in front— inside this other folder.
But whatever.
Let's do— by the way, sometimes I prefer typing it out instead of copy-pasting it just to work on that muscle memory.
Let's create a new thing, see if this doesn't explode. I'm, I'm just streaming on YouTube. I'm using Zoom to stream.
Turns out it's great for streaming, but, uh, no.
Yeah, I drew 6 hours this week. Uh, that keeps me sane. That's, that's the thing. That's what I get most excited about, honestly, every week is, is drawing and painting.
Nothing to do with tech.
I'll be coding all of it. The form, the backend submission, the email. I think I can build most of it today. I have 7 hours or now 6 and a half, and I think I can build most of it in that time, but we'll see. You know, honestly, a lot of, a lot of like the time it takes to build is you just get stuck on a bug for 4 hours. So you never know, you know, sometimes it ends up taking a lot longer than you think. But yeah, if I, if I don't have any of those multi-hour delays, then I think I should be able to finish. Yeah, definitely by the end of Sunday. Stuff like this also takes a long time. This is one of the slowest parts about development is just waiting for, you know, all the packages to download. So just to talk a little bit about this, and again, I highly recommend even if you don't plan on doing anything, Like do this, like why not? You know, just do rails new, make a name up, like just run through the process. Like just start building momentum. You know, you don't have to run a 5K this weekend, but you, you know, go for a walk, get, get your body moving. So yeah, when I do bundle install, which I think was part of that command up there, basically what this, each one of these is a package. Of code, kind of a library of code that you can kind of reference. What this means is I don't have to write that much code because I get to use, for anything related to zip files, I get to use RubyZip. For anything related to other things like testing, I can use Minitest or one of the other testing frameworks. PG, I think, references Postgres. The database, you know, obviously I'm not writing like a database integration. And so, you know, there's kind of a thin, if you think about it, there's like a thin app layer, which is what I'm building and, you know, a database and things. But like, if you think about the amount of infrastructure that I get for free because of open source, it's like pretty amazing. You know, I, I have to do almost nothing. You know, internationalization is built in, parsing of HTML is much easier, you know, and you don't have to build any of this stuff.
So even when I say I'm, I'm, I'm built, you know, When you say, you know, co—
is, are you coding it? Are you not coding it? Like arguably, arguably I'm not coding 99.9% of the app, right? Like, you know, there's a joke, like if you wanna make an apple pie from scratch, first you have to invent the universe, right? So there's always an assumption that you're building on top of, you know, the shoulders of others, right? So yeah, so that is all the Ruby stuff and Ruby is kind of the backend server language for the app server, the web server., and now I believe it's downloading all the JS packages. So same thing, but just on the front end. Um, so that will also take quite a while. Actually, it might take longer cuz I believe front end stuff is now kind of more, uh, complex than backend stuff, but we'll see. Which phone do I use? An iPhone, uh, something. I don't know what the number is, like a year or two ago.
10, 8, I don't know.
They should reset.
I feel like they should come up with a different system. It's like Final Fantasy now.
6. I have an iPhone 6.
Yeah, that seems, that seems reasonable to me. Does it say? No, I guess they don't write it anymore.
Remember they used to have like the things like where it show you like the Apple like, uh, certification and all that stuff.
Now it's just like the nice Apple logo. Pretty cool. But yeah, I just have an iPhone.
How is building a website app Using drag and drop tool different from coding? I don't honestly, I've never used any of those drag and drop tools, so I'm not, I'm not sure. But I always say, look, if customers can't tell, shouldn't matter. Doesn't matter what language you use, doesn't matter. And nothing doesn't matter. Like all that matters is did you solve your customer's problem? And by the way, you can, you can find the original Gumroad source code. I built Gumroad over a weekend. If you just Google Gumroad V1, you'll find a GitHub repository that's public and you could see exactly what I did that weekend and it worked and it got me a million bucks from Silicon Valley VCs, literally off that, the code that I wrote that weekend. So the plan is not to raise a million dollars in VC for this project, but certainly could given where the market's at. So look, everything seems to be ready. So let's go on.
The next step of whatever the tutorial is, which is to, to go into the app.
And yes, I know I can change this, but who cares?
I can do that at the end. Oh, switch to the master branch. I guess their tutorial still, still generates a master branch by default. That's kind of annoying.
Oh no, I know why, because GitHub did that.
And, um, hmm. So maybe I should do that then. Um, someone actually gave me a hint on how to do it.
Oh yeah, move I think is the function, and I basically just want to move the verification letters folder.
How do I do this?
What?
Oh no, I'm already in there now. CD.
So this goes backwards.
I'm back in the main repo.
I can tell because it's the main from GitHub. And then I can do—
take this and just move it here. Oh no, why didn't that work?
This—
hmm, why does that not work? I'll just do it manually. Code verification letters, basically take all these things Move them there. I think that should work. I'll replace the README. All right, let's see, let's see.
That didn't explode everything, so I can now do whatever this is. I wish they told me what this does, but whatever, something to do with Platforms. Who knows? Again, like, I think it's really important to look like— I don't even know who— like, it doesn't matter.
You don't have to—
you don't need the answers to every question to make progress. So yay, someone already set up Super in their domain. Awesome, people are doing stuff. Okay, create the database.
I'm a little scared about doing this, but let's see what happens. And then I already have pg_jam, I believe, in the Gemfile, so this might be an out-of-date tutorial, which is a little scary, but it's not a big deal.
Okay, now reinstall.
Let's do that.
Yeah, you can, uh, email me if you want to be a mod for the Discord or ping me in the in the, uh, channel. I'll just pick people based on how useful they already are. So like, don't ask to be useful, like be valuable to the community and then ask.
Secret, uh, to being successful at life. I actually talk about this in the book, by the way. I have a book coming out, you might not know.
Uh, you can check that out, minimalistentrepreneur.com. Forward slash preorder if you want to preorder it, or you can go to Amazon, or you can wait until it comes out and see if people like the book or not before you decide to buy.
Cat, don't know what that means.
I guess it probably means like to print or something like that.
Seems reasonable to me. All right, generate a welcome page. Let's do this. And then I have to write stuff.
Oh, great.
App/views/welcome. Okay, so I need to create this, so I can just touch that. Create it, and then you'll see that it now exists.
It's just a blank file.
And so yeah, I'll type this in. My copy-pasting or my typing is a little slow because I guess I'm streaming via Zoom, and that just—
again, I only have like a 13-inch MacBook, so it's not exactly speedy. It actually—
it is an M1. I guess it should be better, but whatever. Problem is the better you make the hardware, the better the software, and just, it's a never-ending thing.
So routes, let's go to routes.
Config routes would be there.
Uh, and this is where you all, you're kind of, you know, when you visit a URL, like if you go to verificationletters.com, Google says, okay, it's pointing to this set of servers, right? This app. Um, but you know, if you go to /thanks or /about, you know, you kind of have to specify, well, what part of the app is actually serving, serving that content. So that's what this does is basically if you're going to root, which is, you know, slash, right? Like the main thing, point to the welcome controller and specifically the index method, right? So you have this welcome controller that we spun up. Which currently does nothing, just forks off the application controller, which also should basically be doing nothing. This is the magic of Rails. And then this should be rendered by visiting root. And finally, we can spin up the server.
Let's see.
Cat is short for Concatenate.
Gotcha.
See, I'm learning stuff.
So cool. Looks like the server might be working locally, right? So you can't go to that website, but you know, I think soon we'll, we'll, we'll, we'll get it so that if you visit the website, you'll, you'll see this. Hopefully people are following along. 'Cause, uh, you'll soon have your own app, maybe for the first time deployed onto the internet. Uh, or maybe not.
I don't know what's happening.
So slow.
Oh, it's happening.
Okay. I guess there's a new feature where it shows me this annoying thing. Um, cool. So this works locally. I have a, you know, I visited the index and now I have hello world.
We're done.
We're done.
So I think, what do we wanna do next? I mean, let's keep going with the tutorial.
I don't even know what is next.
I guess we still need to deploy to Heroku.
I guess that's important. So let's do that. Previous, blah, blah, blah, blah.
Not needed.
Rails 12 factor. Is that in there? Presumably not. Nope. Specify your Ruby version depending on in your Gemfile.
And that me, by the way, is just doing Command+P to do— again, I don't know what that is short for.
Maybe someone can tell me.
Um, but that just allows you to kind of quickly search for files.
So That's what I did there.
Um, but yeah, it looks like I have Ruby 2.7 specified. Probably doesn't make a difference with the difference there, so let's ignore it. Normally, you know, if you're getting into point, point changes, like doesn't matter.
Mostly kind of security bug fix stuff, vulnerability things.
Um, cool. Did that.
I know I'm there.
Oh yeah. Let's commit it to GitHub. Um, so GitHub Git should already be set up. I'm gonna create a new terminal window. So this is kind of running the server locally, and then I'm gonna have this new terminal window. Uh, so you can see it's running the server via kind of a Ruby process. And then this new thing, ZSH, is just something I use, but basically just means terminal with some nice prettiness. Um, so let's do this.
Let's add.
All the files that we've done so far. Oh, does not have a commit checked out.
What? I don't even know what that means. Maybe it's because I didn't do this. Let's see what happens if I do this. Re-initialized existing. Okay, whatever. Oh, maybe it's 'cause I, the commit history got effed up and I, ah, that's weird.
I don't know.
Does not have a commit checked out. Ah, maybe I can just skip it and see what happens if I just do this.
Nope.
I don't know what this means. Never seen it before.
Command palette. Man, this is great. I'm learning more than you all are learning.
Let's see what's the issue. If you have a subdirectory with the Git— you'll see this message. OK. Something to do with the subdirectory. The git—
.git—
um, do I—
will I—
name.git? No, I don't know. That's weird. I haven't seen that ever before, but no worries, we'll figure it out. Don't know, maybe it has to do with gitignore. I accidentally created a directory name inside the repository. You don't need to delete. You just have to do—
okay, there you go.
Let me do that. Just delete the git directory. I don't really need it.
So that is probably what happened is my guess is when I cloned— ooh, it's a directory. The way you get rid of directory is this means remove, RF, which I believe just means remove folder to make sure that's what— it doesn't allow you to remove folders unless you explicitly say so.
I guess for kind of convenience or security or whatever. Um, let's do that.
Boom, that's gone. So this invisible dot means it doesn't show up in the file system. You got your, your kind of computer has all sorts of these files laying around that, you know, need, are, need to exist for configuration purposes for the computer. Um, but humans don't need to know about them.
So that's what that means.
Oh no.
Still broken.
Not a Git repository.
Oh, probably cuz I deleted it, which makes sense. Uh, so now that I deleted it, maybe I have to do git init, then do git add everything. Nope. Still happening.
Weird.
No, there's no subfolder. Yeah, that's what I thought I did.
Is it? Am I in the wrong? Oh, I'm in the master.
Why did you do the master?
Weird.
All these engineers are telling me what to do.
It's great. I don't know what all this crap is.
Rm git, get rid of that file, and then do git init to reinitialize it.
I thought I did that.
And then do git commit all the files and just say init as the message.
That's just all the files. And this says, this is the message.
Oh, didn't work.
Git add.
Yeah, it's not working.
I don't know what's going on. Strange, very strange. What happens if I just skip that step? Oh, I have an app. Neat.
Cool.
That is really strange. I don't know. Hmm, weird.
Well, this is what happens. This is life. This is reality. This is what makes people give up, but I'm streaming live, so I cannot—
gotta keep going. So weird. Anyways, git add. Yeah, that's not working. Yeah, it's probably, probably effed up when I did the, uh There's no, there's no ver— oh, maybe there is. Let me make sure.
Oh yeah, that's probably what it is. That subfolder had some Git stuff still preserved because I—
yeah, because—
okay, that makes sense.
All right.
So if I—
oh, I deleted that so that now this should work.
Yes.
Added all the files. Thank you everybody. Um, Marinus, thank you so much.
And everybody else who also tried. Um, 5 of you also, I think, had the right answer. A bunch of you did.
I was the last. I told you I'm not that good of an engineer, but I'm still gonna be able to build this thing. So, you know, the more mistakes I make, uh, the more, uh, less excuses you have, right? So git commit, as I mentioned before, all the files, which I think that probably already did, but whatever. I normally, I refer, I like to do it anyway cuz I'm lazy. This is the message.
I'll just say init for now.
And then this is just chains, you know, a new function.
This just pushes it to GitHub. So this should push if it works. Oh, it didn't.
Oh, it's because I have to add it.
I have to add it now. So I will go to GitHub, go to this, and then what I need to do is add this as a add existing GitHub project as origin or whatever. There you go, this should do it.
So I'm just adding this to know that when I say origin, I mean git@github.com.
This is the repo, that's my username, and then that's the repo name, .git. Try that again. Git push, git push origin, uh, head. Do I want to continue?
Sure.
Oh, I'm not set up on GitHub. Let me stop my screen share and make sure that I'm set up properly. That's weird. Normally I thought I would be, but— let's see. Get pushed because of that, so let me just add SSH key there. I'm just doing this without sharing my screen just in case I do something stupid and reveal something I shouldn't. Oh, that's weird.
Yeah, maybe I'll just create a new repo. F the old one. F the old one.
Um, so what was the command for that?
gh—
I don't think I do have the— okay, so I'm gonna do Actually, let me start sharing my screen again.
All right, so I do gh repo create. That's the name. I don't need a description.
Let's make it— I'll make it public, whatever.
Yes. Oh no, it already exists. All right, let's go delete it.
Let's delete it and start again. Bye-bye. Awesome.
Okay, so I'm just gonna run that command again.
gh repo create, verification letters, public.
Yep.
See if that works. Oh no, remote origin already at what? That's annoying.
Okay, maybe I'll just do Let's see what happens now. I don't know why this public key thing—
why is everything breaking all of a sudden?
But weird.
No worries, this is life. This is what always happens. Yeah, this is weird. I normally haven't seen this before. So I will have to probably just—
it's been a while, I guess, since I committed to GitHub.
So let me just set up.
And the tutorial that I'll use is I just Googled add new SSH key to GitHub account.
Ghssh-key-add, and then I'll just do—
oh, I think it's because I don't have the auth set up on, uh, on GitHub properly. I guess they switched to two-factor or something. So I'm just doing that now. Okay, this looks like it's working.
All right.
Weird, still getting a public key error. Strange. Get push origin head. Maybe I should build it with no-code.
Yeah, that's no fun. All right, let me add that again.
So I go to my GitHub settings, go to my SSH key place. There are no SSH keys associated with my account. What? What? This seems wrong, but sure, whatever. Very strange, very, very strange.
All right, I think I added my SSH key just using this document, Adding a New SSH Key to Your GitHub Account. We're gonna try again.
Git push origin HEAD. Oh, shoot. It worked. All right, time to share my screen again.
So just to reference, I just copied this public key and pasted it into GitHub, and then I was able to push and it seemed to work.
And that can be checked because if I go to the repo on GitHub, which is public, I believe, so everyone should be able to do this, but boom, you can see my initialization commit with all this stuff that came from that Heroku tutorial. Boom. Awesome progress. Moving on. I like closing tabs if I don't need them.
So that is now, you know, connected to that same repository.
Let's refresh, make sure that's still true cuz you know, we, we kind of messed around quite a bit. Makes sense.
Awesome.
Yeah, looks like that's set up properly. So let's keep going. So this is where I was and I just did that. Okay. So I did Heroku create. So let's just do, let's make sure that that's there. It might actually not be there because the Git I set up afterwards. Oh, nope. It looks like Heroku's there. Secure Coast is the name of the repo, I guess. Secure Coast. Sure, whatever.
Um, so let's do that. I guess this is the command that we need to push. Just like I pushed to GitHub, I'm now going to push to Heroku.
Oh, didn't work. So let's, let it, let's try that again with another Heroku create. Probably due to that other issue. All right. Warm lowlands it is. I'm just gonna run this again to see what happens. Doesn't exactly show the right name, so that's a bit weird to me. And my, my guess is this is gonna error, but we can deal with that in a second.
Yeah.
Remove old Heroku.
Origin, et cetera.
Git remote remove or this looks better.
Stack Overflow.
Okay, I'll just remove it. Git remote.
Wait.
rm heroku. Yes.
rm heroku.
Boom. All right.
And when I want to add it, I'm gonna use this.
I'm gonna do git remote add Heroku, and then it's gonna be this URL, right? And then we're gonna push again. Oh no, failed to push. What?
Why not?
Oh, is it master now? Cool. Yeah, it is.
So let's do—
ideally we would be main, but we can worry about that later. Boom, it failed. Great. Let's see, why did it fail? The Ruby version you're trying to use does not exist, uh, on Heroku 20. All right.
Let's see, what do they support? 2.7.4, I guess. Sure, not a big deal, I guess. 2.7.4 should work.
And let's just do another bundle. Every time you make a change, you gotta bundle.
Ah, see, and then change the Ruby version, which I believe you can do something like— no, not rbenv, Ruby v. Do I have this? No, I don't. I don't want to use it then if I'm not— oh, everyone recommends using it. Weird. I think I have rbm, so let's try this. rbm use 3.7.4.
If you're curious what I'm building, check out the Discord. Um, you'd have to go to my Twitter, I think, uh, to find it at Sahil Lavingia.
Um, but there should be a link, um, or someone can paste the Discord link into the, uh, into the chat.
Okay. So we're now using that.
Let's try again with that bundle.
There's a joke in programming, like the goal is to not fix the problem, but just find a new problem. You know, it's like a sigh of relief when there's a new bug. It means you've made some progress.
So yeah, that's kind of how I feel here. Let me add— is there a way to add the Discord link? I don't know. Okay.
While that's downloading, let me cruise.
Twitter and Discord and see if there's anything I need to respond to. I have 20+ DMs, man.
I appreciate it. 20+ probably means a lot more than 20.
That's okay. All right, still downloading.
FFI. What is FFI? Why does it take so long? Must be important.
Something to do with Ruby. Probably not fatal familiar insomnia.
Programmatically loading dynamically linked native libraries. Does anyone understand any of these words? Binding functions within them and calling those functions from Ruby code.
Whatever. Sounds important.
Sounds like a lot of work. See, look, this is how many people have worked on verification letters already. These are all my employees except I don't have to pay for them. They've contributed more value than I have so far. We got Meh as well.
Thanks, Meh.
Appreciate it.
Yeah, I'll go paste the Discord link in the thing. Give me a sec. I really not put the Discord link on Twitter. I'll do that, then I can just point people here. Oh, what have people said? Yep, that's true. I don't know why my Discord is so slow to open, but what's slower, downloading all these things again or opening up Discord? That's the race.
Oh, we're at W, almost done.
Oh, Discord lost. That's pretty sad, Discord. Pretty sad.
Again, I remind everyone, there's so much work to be done to make stuff faster and cheaper and better and smoother and slicker and simpler and more pretty.
Awesome, just finally loaded.
I'm sure I don't blame Discord.
I mostly blame the fact that I'm streaming. I think that's really doing a number on my computer. I'm a little worried that I'm not going to be able to make it. I might have to switch to Zoom only or something again. This did finish, which is good. All right, so what's the next step in the tutorial? Did I do this or not?
I forget.
No, it failed, right?
Oh no, why did this happen again?
Oh, it's because it's Oracle Master. All right, still failed. No worries.
Why am I trying to—
no, why am I trying to install 2.7.0? I thought I changed that. Is it because of this thing? Do I need to change this? Sure, I'll change this. A lot of these things, but I think this is a different thing. Yeah, I don't know why.
Weird.
Maybe I have to git commit or something, git commit that.
So I'll just run this. This is like the command that Simplifies adding all the recent changes with a checkpoint commit and pushing it to GitHub.
All right, let's try one more time, see what happens. Let's see if Discord has spun up since. All right, let me put the Discord group in here. All right, I'm gonna go close this again. Hey, look, it's awesome that people are doing it.
Great.
Yeah, I don't know, I don't know what's going on, but we'll figure it out.
Oh, what?
I ran— see, look, this is, this is the thing with engineering.
Like, you never know.
I literally pretty sure I ran the exact same code. I guess maybe this is the difference, but I'm pretty sure I just ran the exact same code and it's now using Ruby. Or maybe it was the other change I made, who knows.
But we are—
looks like things are happening. Different error at least. You know, this is kind of doing exactly just what I did locally, but now on that Heroku server should be faster, I think, cuz a lot of their stuff is probably more efficient than what I have going on.
Okay, let me follow up to that tweet.
Okay, cool.
Sorry, I don't speak Arabic. Could you say that in English? Actually, I used to be able to read Arabic at least, but I did buy myself a breakfast burrito, so while this takes some time, I'll be eating burrito. All right, we're an hour in.
We set up hi@verificationletters.com. We have the domain. Not too bad.
Not too bad. This might be the old Heroku thing. We'll figure out if it is or not.
Uh, meanwhile, what else can we do? I guess we can maybe set up the DNS or something like that. Point verificationletters.com to this. Place.
So let's do that.
Verificationletters.com could not be created because I need a credit card.
Oh great.
All right, I'm gonna stop sharing my screen for a sec while I do that.
Um, let me do account settings, billing, add credit card.
That's kind of a nice UX.
Uh, California is where the card is at, I believe.
Hopefully.
All right, I added that. Let's go back and see if it lets me add a domain. Yep, cool. So let me share screen again. Awesome.
So I just, I just did that step, just typed in verificationletters.com. They gave me a DNS target. Copy paste your DNS target somewhere. Where?
Probably Google, right? So let's go over here.
Yeah, Netlify is awesome, but, uh, I'm using what I'm, what I'm comfortable with. But yeah, use whatever. Netlify is great. Cloudflare is amazing. Vercel is awesome.
Uh, there's a bunch of good ones. So create new record data. Where do I put— let me close these. I don't need this right now. Where do I put the DNS target? I've never seen it. Exactly like this, um, but whatever. Configuring.
Let's see.
Oh, that's cool, you can add it from the URL. Oh, I need to add these. What happens if I do go up here, host? Oh, sweet, it worked. Okay, let's, let's, uh, shall do. Uh, yeah, might as well do that. See what happens.
Boom!
Look, everyone can now visit my app. I just visit this URL.
I'll put it in the YouTube chat.
Boom, it's live!
It works, it does the thing.
Now I just have to make the app do the thing and we're, we're done. So easy, in an hour.
Not bad, I think. Um, but we— what we actually want is we want verificationletters.com to go there, which it currently doesn't do. So let's make that happen. Post www.letters.com. Not found.
All right.
That's good. Oh, I have to do this.
Okay.
Maybe if I do it through here, it'll actually tell me the instructions.
Oh no, it's used by another app, probably another app that I made. Is this not the right, uh, Name for it. I thought this was this one. Do I have two? Oh, I do have two. Did I add it to the wrong one? I must have, I guess. Let me delete this one. This is warm lowland, so yeah, I'll delete secure coast.
Hi.
Oh, I still have two. I'm gonna delete this one.
This feels like the wrong one for me. So let me delete this one as well.
Oh, this is where I added it.
Maybe that's what I did wrong. Hopefully I don't regret doing this. I might. It's all recoverable though.
This has more activity, so I, I feel good about this one.
All right, let's go back.
Cool.
Let's add domain again. Done.
All right.
If I refresh, is it there? Yep, it is. And that's my DNS target. Great.
All right.
You usually configure a new CNAME with your DNS provider. All right. So it's a CNAME. The name can presumably be www. And then the domain name presumably is going to be this with the period at the end, right? Which is— my version of that is this. No, Heroku DNS. But whatever, I can update it easily enough.
Blah, blah, blah, dot.
HerokuDNS.com. All right, HerokuDNS.com, right? Something like that. Custom records are saved.
Do I need to do other things?
I think these are just examples, so I think I could just do that one. I guess he did add www, but maybe that will lead to some issues, but we'll see. Okay, alias, alias, CNAME alias, alias. Um, I can do that too, so I will do record alias, do nothing, do that, and then do the same thing, which was this, but then replacing app with DNS and this with the period, right? Was that right?
Yeah.
Oh, it's invalid.
So no, I'm not supposed to put the target there, I guess. Or A name, alias or A name. Oh yeah, I need to add the wildcard. Okay, let me do this first. Using the wildcard CNAME. So CNAME wildcard CNAME like this. Oh fuck, why did it wipe it?
All right.
Scroll up to the Discord if you don't know what I'm building.
Join the Discord and go to the announcements channel.
You'll see what I'm building.
Or just go to the beginning of the stream.
I, I'll get into it. You can always come back.
Um, so cool. I did that.
Uh, custom domains. Is there anything else that I'm supposed to do? Probably, um, what I should do is add the www. It feels like I'm supposed to do that, so let me just— all right, yeah, let me do that. Cool. Yeah, see, this says it's supposed to be a CNAME and it's supposed to point to this thing, but it doesn't let me. Warm chamber. DNS target. I don't think— well, one way to find out.
Let's see if it's working.
Stuff always gets confusing to me.
Nope.
Normally I haven't seen that. Normally they just give me the CNAME, so this is kind of weird, but presumably I need to enter this here. So I'll do that for the CNAME. Or sorry, I should— maybe I should have done this for the CNAME. www.cname and then that seems to be what they want me to do. And then I'll do this here as well. I can— I'll try to create the new record. Oh, there's more. There's a Tesla. That's cool. Oh no, that's TLS.
So I guess that has to be an IP address, which I don't have.
Um, weird. I don't know. I, these instructions always confuse me. Use the target from Heroku console. Okay, cool. Yeah, I'm doing that, right? I'm using this.
Um, so I set that up, which is the www with the CNAME, but then I don't know what alias or A name, like It doesn't— it clearly doesn't let me enter this as the A name.
I'm not sure exactly why, but that's okay. Let's try it with the www at least.
Oh, boom! All right, cool, works. Um, but if I remove the www, in theory it won't work, right?
Oh nope, it does work. Really?
Someone can test that, but it looks like it's working. Boom! Now you can go to verificationletters.com and have the, have the app. So we've done that. Uh, great.
Um, let's do SSL because normally it's pretty easy, so might as well do it.
This might cost money.
Hobby or above tier?
Oh great.
Okay, let me go, let me upgrade my tier. You technically, I guess, don't have to do HTTPS, but I feel like it's good practice, good thing to do. Um, so let me upgrade. I don't even know how to upgrade my tier. Do I do it from Dino Formation? Probably free dinos hobby. All right, that was pretty easy.
Settings.
Uh, all right, one domain failed validation. All right, that's fine. Yeah, see, that's the issue is that I'm not able to enter. Do I need it? Can I just get rid of this? All right, secure. What happens if I remove this though? It's going to fail, isn't it? Yeah, see, that's going to fail.
So I need to— I think the way I can make— I can fix that is I might be able to just name servers.
Maybe I can just do it on here, uh, if there's a way to just redirect, you know, from— let's see if there's a way. Yes, sleep page. I don't need that. I don't need that.
Go away. What's this?
Is that— no, that's Oh, maybe advanced. Oh, that's scary.
Yeah, maybe we'll just go with the www for now. I mean, it's not ideal, you know, but, uh, yeah, I know I have to set a redirect, but how do I do that? Can I do that?
Redirect from root to www. Website forwarding.
Okay, sure.
Website setup forwarding.
No, no, no.
Forward from just that to www.
Daniel, I don't have the answer to that question. I honestly don't know.
We'll figure it out. Yes, I'll do that. See if that works. So now in theory, if I go to this URL, it should redirect me to the www.
Boom! And it's secure, and it seems to refresh. This is updating as I refresh it, so that works awesome. Uh, so I can close that tab. I think I can kind of close this one too because the domain is currently set up.
Right, I pushed to Heroku.
I mean, that kind of works, so great.
Um, don't think I need to do— worry about any of this kind of stuff. Awesome.
Uh, this is my local, which is still around, still alive.
Close this, close this, close this.
And this is the production, so I'll keep that open, I guess. Um, and we'll get started, I guess, with the actual app. Pretty cool. I feel like made good progress for an hour and 20 minutes or so.
Uh, let me go this way.
Awesome.
Cool.
What should I do?
Should I start building? I'm tired. I don't wanna build.
I don't wanna write code.
It's Saturday.
Um, yeah, let's look at the Notion. Notion gets me motivated. I don't need this anymore.
Everyone saw that demo of Super. I don't know what this untitled thing is. Delete that. All right.
Build product. Yeah, man, there's, I don't have any excuses. I'm trying to find excuses, other things I can do. It looks like I just have to build. So let's do it. Uh, let's go to Figma and open up the prototype and hopefully this doesn't make my computer implode.
That's done.
So this is the Figma prototype, which folks have seen. You can find it in Discord like always, but I don't want the prototype right now because I need the actual, you know, look and feel and all the numbers behind the design because I need to actually start building this thing, right? So let's do it. Um, so I need— I— there's a homepage, which I guess already exists, which is the welcome. Welcome is not ideally what I would have chosen. I would have picked like home or something like that, but not a big deal. Um, and then there's layout. Layout has like the overall, um, you know, so when you visit the homepage, it renders this, and then in the place of yield, it renders this, right? Which is why you saw If you go back to, you see this title, right? And all, if you look at the code, you'll see it, right? It's loading. This is all from that, you know, this bit, all that is coming from application, right? All this stuff. Boom.
See it.
And then the body yields it, you know, kind of renders out this stuff. And there's some other stuff, I guess, these are some Chrome extensions that I have installed that are doing so.
Some stuff, I guess, probably when you open this itself, but hopefully you get to see that.
Uh, yeah, you're right, Miguel. The hard part is done, honestly. Like now that, you know, you, I feel like you've set everything up now.
It's just moving forward.
The database will be a little tricky, I think. It's been a while, but, uh, but at least I can build a static front end probably in like an hour, you know, by noon we can have like a website that looks like it works even though it may not. Work. And yeah, there's no, you know, use Super, use WordPress, totally fine. You don't have to write code if you don't want to. Um, I enjoy it, I think it's fun. Um, but I'm also, you know, people are different. So you can see if I change that and refresh, boom, now that's verification letters, that comes from the title. So just to show that it's, it works and it's pulling from here. Um, and so normally what I do, and again, I only have this screen, so I have to just tab back and forth. Normally what I do is I just type all the most, most kind of the, of the HTML that I kind of know we're gonna need.
And then I worry about CSS and, and then kind of go back and forth.
So there's effectively one container, right? Which is like this content. Everything lives within this kind of like, you know, wrapper container view. So section, let's call that like the wrapper.
Let's put this all in it.
And just to show that it works, I can open up assets, stylesheets, and then welcome has their own, right? And then I can just do wrapper, uh, you know, width, uh, and whatever the width of this is. So the width of this is about 887, which is oddly, you know, maybe we can make this nice and round. We can make it 900. You know, and then we wanna center it, which is the way I center it is I just do margin: 0, which means this is, you know, top and bottom and this is left and right. So 0 padding on the top and bottom and auto basically just means center it, right?
50% on either side.
If you go back here, boom, it's now, and let me just add a background to show you, let's make the red. You can see that it's doing stuff. There's some annoying padding stuff that's happening. This is due to like some CSS styles that like browsers have built in, like this padding. Um, so normally I just find a CSS reset, basically gets rid of a lot of this stuff. Uh, Eric Mayer has this famous one. So, you know, I just take it, copy it, and, you know, create a new file called reset.scss.
And put that in there.
And this should automatically compile in that order.
Oh, that's the actual page.
So you can see, boom, it's all gone. You know, you saw that styling that was kind of there, you know, from this header, et cetera, like that's auto-added by the browser. The reason not to do that, not to rely on those is every browser does it slightly, slightly differently. So you wanna do it yourself, right? So that kind of resets it, but boom, like, you know, I have this like centered Time to think. Um, that kind of works. It's also kind of ugly, so let me remove it. And actually, in this case, I kind of do want a padding, right? Because there does kind of seem to be some amount of padding above and beyond. This is, is going to complicate things, this kind of logo. Um, but you know, for now, let's add some padding. So I'd normally do, you know, some nice round number. It doesn't really matter. I think in this case I'll do 60 or something like that. I like 30, 20, 60.
Nice round stuff.
This feels quite like wide to me. Partly it might be because Figma, you know, everything's kind of just designed— oh no, I use the height. Oh, that's why someone was probably watching me being like, you're an idiot.
So that's 470 is what I meant to do.
Let's do 600.
470 feels really tiny.
Um, actually no, let's do it.
Whatever.
We can always modify it.
Um, and then we have the h2. I generally, like, you know, I used to love semantic HTML like this, but honestly, like, it makes your life hella over time. It's better, I think, to, for everybody to just use class names. I know this is uglier. Um, but, uh, yeah, sorry. What I'll do is I'll create a new class called the header and then I'll just type verification letters in here and then I'll style the class to actually have that cool logo. There'll be a header and that'll have some stuff in it, font-weight bold.
This is going to have 34 font size, 34 pixels.
Font family is gonna— I don't even know how this will work.
These are the fonts that I use almost every time. Don't know why Arial would be ahead of Helvetica.
Uh, yeah, it looks like I don't have that font, so we can figure that out later. Um, how to get that font in there.
And then we have a paragraph. We don't need the time is now anymore, so let's just replace it with this.
I actually have it bolded here, so let me bold these, uh, strongs.
This is a placeholder pricing, but I think I'll just stick with it. Um, and then I guess I can put both of these in paragraphs. All right, so you got that, and then you're gonna need a form. Uh, will this be part of— yeah, sure. Need a form which will be form, and that has—
seems to have label, which is legal name, as an input, which is text. Doesn't have a placeholder. Just do that, I think.
Um, and then there's going to be more of these, right, over time for all these.
So this is going to be primary resident address.
It's going to be, I'm verified because dot dot dot. Supporting documents, email address, and finally payment info. Then you'll have a submit button, so button type submit. It says submit information for verification. And ooh, it's ugly, but it has all the things.
And then there's a footer, right? So as I mentioned, I like having the kind of, uh, email there for folks to be able to contact and get feedback.
So I'll add this. I'll change These two, is it bullet or there's a, or disc or something? I forget what the term is for this one. I'll try that.
See what happens.
Oh, nailed it.
Uh, no, I didn't. I, I did technically go to school for 4 months, but no, I learned, I learned to code, uh, honestly just doing stuff like what I'm doing in front of you. This is the best way you can ever learn.
You don't need school to, to learn, in my opinion.
So let's do margin-top.
Let's add a border to the top of this thing, which is going to be whatever this color is, E5, which I would normally like to have some tint, but we can worry about that later as well.
Um, and you're also gonna need some padding. So this is the margin and this is the padding. Padding is kind of within the section and margin is outside of the section.
Highly recommend Lambda School as well.
Awesome. So what I want to do is make everything Helvetica cuz I like it. So I'm gonna just move, you know, in the application, which is kind of what I consider kind of like the global file. I'll make everything Helvetica Neue.
Boom.
And then back in the header, or we can do, you know, we can make it so that all labels and all paragraphs are block, which basically means that they all go on their own line. And I would like the paragraphs to have a margin top of like 20 pixels or something like that.
So they look, you know, nicely spaced out a little bit like this. Oh, and then the color, I actually don't wanna be using whatever black I wanna be using this.
So let's make the default color on the application, this color from Figma. And then once I do that, then I do want to make the header black, right?
So now I go in and say, actually, I do want this black. And then the form also wants some margin-top.
And then finally the button— not finally, there's a lot more to do, but I'm going to make the button, I'm going to do width 100%, right? And then obviously it looks quite different. There's a bunch of stuff about this button, but not too hard to do it.
Um, what I want to do is detach instance so I can easily get it.
Um, it's a gradient, gradient teal.
How do I go to the style definition? I pulled this from the Gumroad design system, I think. Um, here it is.
Gradients.
How, why, why can't I, how do I see the gradient? Weird. Um, there should be a way to do it. Oh yeah, here you go.
So awesome.
So let's do it.
Gradient.
Again, all about Googling and copy pasting. This seems like what I want, but I want it to be from bottom to top.
Um, but whatever, we can edit it. But this gives us the overall thing that we need, and we can test by going back and hitting refresh.
Ooh, pretty. Actually kind of looks cool.
Maybe I'll keep it, but, uh, nah, I won't because I want to follow the system. So let's—
first of all, let's do—
make it, you know, it's vertical, so That's kind of obvious. And then let's do, oh, hex. I want a hex. So from one side it's this, and then it ends at the other side at this. Pretty faint, subtle. It looks like I got it flipped because I want it to go actually from top to bottom. And that looks good.
And then because it's a button, it, the, you know, browsers auto add that, which I think the reset style should actually deal with.
I don't know why it's not in here. Maybe it's a little outta date, but I would normally add this and just do outline zero. I think we could do that. Nope. Border. Is it border?
Yep.
That's my addition to the beautiful reset stylesheet. Uh, let's add a radius so that it's rounded.
And how rounded is it?
Looks like 4 pixels. Small to me. I think 8 might be better.
It's a bit too childish. This is a professional service. Hey, non, you should just learn coding. Why, why do you say other than coding? Why, why do people always say though, can anyone help me learn marketable skills other than coding? You're inherently telling everyone, you know what the most valuable skill is to learn. You're choosing not to learn it.
Um, everyone learn, everyone who knows how to code, learn to code. Um, just so you know, no one was born with this ability.
Uh, cool.
So that is awesome.
I'm just trying to get the font size.
I don't know why it doesn't show me what the font size is. Maybe if I detach it. Here you go. 17 font family.
Can you copy CSS directly from Figma?
That's pretty awesome. I didn't know that.
Uh, how do you do that?
Where's the code for For that. I've never seen that before. Is it hiding?
It was in export.
And can I do export now?
Preview.
I'm sure there is.
Oh yeah, here it is, I guess. You can—
oh yeah, that's sick. Awesome.
Good to know. Learn something else.
It makes my life a lot easier.
So, oh wow. It's like really CSS stuff. Awesome.
Cool.
No, very useful.
That kind of looks like that button already, right?
What else is left?
Well, there's a border, right?
A border of this. So let's add border 1px solid of that color.
All right, now it's a button. It looks kind of like that button. And now I wanna make it so that when I hover over it and hover, when I hover over it, I want the cursor to be a pointer, right? Like normally, you know this, right?
It looks— now it looks like a button.
And then just for fun, I like adding an active state, which I didn't do in the design. But generally what I do is I just do a box shadow, an inset box shadow, and I do something like a 10% opacity color. And I do, I don't, I honestly don't even know.
I just pick random numbers and I hope that it looks good.
Yeah, it kind of looks like I clicked down on it, right? Maybe if I want it to be a bit darker.
Yep.
Looks good to me.
Cool. Awesome. So let's move on. It looks like everything has roughly this kind of like—
what is it— 25-pixel kind of margin. So let's add that here. Margin top. Oh, I did 25 here. Yeah, so that starts to look better.
Let's do the labels, which will have a similar thing.
Bold.
Are these black? Yep. Color black.
Boom.
And then the inputs, which are currently all text inputs. So I can just literally do this, but if we wanted to be more specific, we can and we will later.
We want 100%.
We want the border to be 1px solid Whatever this is.
CSS, save me. Where's the CSS?
Is it here?
Yes, awesome, wonderful. Is really nice. So I do border-radius: 4px, uh, border is this one, and then it's the box-shadow. There's some other things, but I don't think you'll need them.
So boom.
Oh yeah, height is, is important.
Um, 50px height. 50px.
And it's actually gonna be—
oh, and then if I type, it's gonna be a— it probably, you know, kind of looks a bit ugly. So first I'll add a similar margin-top of 25 pixels, and then I'll add some padding, which I'll just do like 10%, 10. And I'll also do box-sizing: border-box, so the height is always 50.
The padding is too high, uh, in between these.
You can probably tell, actually it's pretty close. So, uh, we'll keep it. This, these look bigger.
These labels look bigger to me.
Yep. They're bigger. They're 18. So font size 18. Oh, that didn't seem to do anything. Maybe the— oh, that's cuz I typed in the wrong place. You know, um, let's do the logo.
So for the logo, I need this image. You know what I'll do? I think I can just make the whole thing image. That way I don't have to worry about the font family, you know, kind of getting the font there.
I don't know why this is headed is like so big, uh, Let's fix that. Oh, it's because this thing has like this. Uh, I wonder if I can simplify it a bit. I don't really need any of that stuff.
Hmm.
What the flip? All right, let's see if I can go into the vector. How do I edit the vectors through this? Yeah, so if I just delete this— oh no, so let's delete all these weird little bits and then move this down. Will this fix the issue? I'm goated for this one. What does goated mean in this context? All right, that looks a lot better. It's— oh, still annoying, but it's still doing that thing. So let's see, why is it doing that? If I cannot resize, maybe it's something to do with What I need is for all these to be frozen so you can— no, see what I, what I really want. Oh, whatever. I'll just, I'll just, we'll deal with it.
Uh, I'll export this. I'm gonna do an SVG and then boom, this is gonna be the logo and I'm gonna move it to the right place.
Assets, images, and we now have it in here. We got this and it looks a bit janky, even though it looks fine in Figma. Hmm, interesting. Let's make sure that it's not actually janky. Let's open this up.
Oh, it is actually janky, probably cuz I, you know, I did all that weird stuff you saw.
Um, so let's fix that. The way we fix that is by deleting all the weird bits that might be causing some weird stuff to happen. And then this is pretty simple. Um, cool. Let's try that again. So let's export the header, call it logo. All right, cool.
Looks good.
So The header is actually going to have this background, which is, it's gonna be this image. Uh, so let's do that. Yeah, I guess I could copy the SVG code, but I don't think that's as nice. Um, rails, do, do, do, uh, CSS background image.
Oh, it knows even what I wanted.
Amazing. It knows. Uh, URL, and then I can just do image— it should just images/logo.svg. Is it that? Seems a bit too easy. And the way to check is to go to inspect, have this header, and then figure out where is this pointing. Well, it's actually not pointing anywhere. It has to point to asset URL. Or image URL. So let's do image URL, and then maybe you probably don't need this. My guess is this should work. Oh, there's something. Uh, I'm also going to add a text indent of -999999 pixels so that that verification letter is just shot off over there.
Don't need it., and then let's make the height of this thing like 300 pixels or something like that.
Um, cool.
Uh, and I wanna make the background red just so I can see it. Um, cool. So there's some issues with this. One is that, you know, it's not gonna ha— it's gonna get cl— it's not gonna clip the top nicely. So I can easily change that by just going top is 0, left and right is still auto, and then the bottom is gonna be 60.
And I could even change this to move it to the footer or something, but I think that's fine. So you have the padding at the bottom. I will probably make this a Mailto link, but, uh, now you have that thing. Um, and actually what I want to do is do this so that I don't override the background completely. Cool.
Awesome.
Um, so let's move this over. And how do I move it over is I basically just have to add, I think it's like 0 and then -100, something like that to move it. Oh, that worked, but not in the direction I wanted.
Yep, that looks like it's doing what I need it to do.
Um, cool.
And I can make the height a lot less. Doesn't need to be that aggressive. Kind of fit in there.
And then what does the actual design look like? So I want this kind of slightly moved to the left so that, that kind of type lines up, which I kind of like that aesthetic personally. So what I can do is move this whole thing by just doing position relative.
And it's doing left. Now let's say 100 pixels. That's way too much. Oh, it's actually not way too much, just a little bit. 90, uh, 80. Too much.
8.
Now if you want to know the pro tip, trip, tip for design, just go like this. You just compare it to the edge of the screen and it's a little too There you go. I think that's perfect. So we have that.
What if I do even less than this, like 20?
Yeah, see, that cuts off. So I need it to be 80.
And then, you know what I should do is I should probably just move this into the header.
Um, because technically, yeah, this is kind of next to it and it'll just be easier. I'm a little lazy, to be honest. I'm going to add an h2 to this, and I'm going to remove the text-indent for now.
Ooh.
And the reason is I have all these things that I need to now scope because I've moved— I actually don't really need any of this, but whatever, I'll keep it for now.
And then I need—
yeah, I actually don't need it, so I'll just remove it.
And then what I need is all the paragraphs have to combat this margin left, or this movement left, so I'll just add a margin left. And then finally—
I'll do margin-top.
Oh no, I don't want to do it.
I'll do it on this one actually.
Yeah. What I want to do here is I'll make the height something so that way it's, it has the placeholder of what the text would normally be anyways.
And that would be good.
It little bugs me that it's not fitting in one line, so I'll update that, uh, in a second. Again, the goal is to make it so that it works. We can always make it pretty and sexy, uh, later. Um, but just to get everything in one page, let's make this 500.
One line. Boom.
Cool.
It's not ideal, but good enough. And it seemed to— I wrote the code well enough so that if I made this kind of, I can fix that pretty easily, which is I just add a no-repeat.
Yeah.
So it, it works. Cool.
So let's go back to just enough to have everything.
Which I guess will be this.
I don't know why that's the case. Um, oh yeah, it's because that's the padding. Yeah, that makes sense. That makes sense.
So I'm gonna make this 470 and then I'm gonna make, uh, the, the Oh no.
What I can maybe do is make the, these things getting a little worried that I'm getting a bit too janky, but, uh, whatever.
That seemed to work.
There probably is an issue if I like turn and go like this, it might lead to some weird thing on mobile, but we can, we can worry about that later. Awesome.
So that's the header. So the header should now be as tall as this, which is, uh, actually we want it to be taller because we want it to encompass both lines. Again, this is not perfect, but we'll go with this for now.
Um, we can, we can tweak it to make it better as we go. Um, but around 230 seems to be, or 220 seems to be what we want. So let's update that to 220. Go back to the design.
Um, let's make it so that when you have strongs, they're bolded.
These, now they're bolded. Um, I don't like that look and feel of these, so I'm gonna make that a bit nicer. I'm gonna do that by making font size 17 pixels. That's already looking better. And I'm gonna make it so that we're gonna use these nice, uh, colors. So let's do that. Color this. I might need to do a font family again. Sometimes it resets the font for some reason.
And then I, I also wanna do, um, I wanna use this color.
To be consistent. So I'm going to take this one and say, when you're focused, border 1px. Or I can just do border color, I guess. Border color. So border color to that. Uh, didn't work.
Why is that?
Maybe it's because it has to be active. Nope, not sure why.
I also think the padding needs to be a bit—
Better. Yeah, that looks better. Change color of input. I don't know why outline none. Oh, I guess you have to do outline none and add it yourself.
Okay, sure.
Yeah, there you go.
Maybe do 2 pixels.
Boom.
Awesome. Um, eh, what else?
What's next?
How's everyone doing?
Any questions folks have?
Um, let me do actually the strip elements. Uh, ha, actually I'll do this first and then I'll end probably this part with Stripe Elements stuff to figure out the rest. So radio buttons, this will be radio buttons, I think. Not text, right? So what is it?
I assume it's radio, something like this. Boom, works.
Um, I'm verified because, and because as I mentioned before, that input is actually being hit everywhere.
So let's just make this, uh, input type equals text.
So now it's scoped to only these input texts, and then these are normal.
So the way you do it, oh, you need a name, right? Why is this for? How does it, how, why is it having multiple for me? Hmm.
Interesting.
I thought I'm doing the same, but it's able to know that it's different.
Maybe because I have to do a radio group, right? That's what I was thinking. Input type radio.
Oh, it's the name has to match up, right?
That's probably what it is.
Name, drone, drone.
Yep. There you go.
So that's easy to fix.
You can just do name equals and verification reason, let's call this. Now it should just do one at a time. Awesome. And let's do this.
As you see, you can click these to update that. That's what these nice labels, um, Then they use IDs, I believe. So for all, I mean, I'm gonna add an ID that says, uh, 1,200,000, 5,000,000, right?
Pretty simple. So 1,200,000 and what was the last one? 5 million.
5 million.
So we got those.
Now let's add the labels.
So I can say label for— label for— label for million, and then this has this text in it, right? So by the way, if I stop talking, that's just because I'm focused, running out of energy to do both. Change the texts. And just for good measure, I'm going to change the supporting documents button to a button that just says upload.
Supporting document.
Boom. It works. I click that, I can click that, I can click that. It's ugly, but it works.
I can upload supporting documents really quickly. I can make this so that this only affects, as I mentioned, button type submits, and then I can have a separate button. That does the kind of stuff that I always expect, which may be something like this cover—
sorry, this cursor, or even this, arguably this active state.
And that way the buttons, I can just focus on specific styling, right?
And just real quick, I guess this is easy enough, I might as well just do it. Yeah, looks good. And then I wanna— I'll probably move the padding over as well. Looks like too much padding to me.
Cuz it's a bit of a, it's like a less intense button. It's not as important. So I'm changing my mind on that and I'll do something else.
Like I'll just do something like this.
Oops, sorry. This is why.
And then same. Oh yeah. And then I can definitely move the roundedness to back to this. So it affects both. And then margin-top as well.
And maybe font-size if this is label-1, which is— oh, I can do inspect. Yep, it is 17. So I can move that as well.
You know, so this just is with the background, which is the padding, the color, text alignment, and the border.
So yeah, I think that makes sense to me.
Cool.
And then I want to add the color here.
So let me add, I think it's this. All right. So that looks kind of faint to me compared to what I saw, but sometimes, you know, you move to the browser, it's like, doesn't work.
So just make it darker, lower the number, makes it darker.
That looks better. Looks better to me.
So let's go back up to this thing. Um, I'm gonna wrap these in reasons, like a div.
Um, so I can add some more global styling to this. So let's go back up here.
Where's the—
do it here. What did I call it?
I called it reason. And within the reason, I want it so that the buttons, the radio ones are floated left. I guess I should probably use Flexbox these days.
Uh, but whatever, for now I'll do what I'm comfortable with. That's a lot actually. Don't need that. And then do label float-right, you know, something like that. Um, and for some reason they're still doing a a little bit weird stuff. 18. Interesting.
All right.
And then what's the color? Is the color black? Oh, it is.
Cool.
All right.
I'm fine with black. Technically it's a label.
So it matches. Um, but I don't know why this float doesn't work. It's been a while.
Um, maybe I should use Flexbox.
What do y'all think? Um, thinking, what should I do? Sure, I'll use Flexbox.
Flexbox for radio button.
See if it gives me any nice example that I can just steal. Not that one.
I don't want a grid, but, ooh, yes, basically this is what I want, right?
Um, great.
So let's see how they did it.
Project attributes, grid row, label. Oh, they put this, they put everything.
Oh, they're checkboxes, but they put them all within the label.
Yeah, it's a little less ideal than what I want, but obviously it works.
And why does it work?
It's because this is just not display: block.
So yeah, maybe you don't need all this fancy stuff.
Maybe this is too fancy. Uh, might be able to get away with less.
And one, by the way, once I finish, uh, Once I finish this, like the static page, I'll, I'll push it to production so people can kind of see it. And then I might take like a bit of a break and come back.
Okay.
So that is display: block. That's why it's happening. Oh yeah. I don't need that.
So.
I guess need that to be inline block. Yeah. Okay, cool. Yeah, I can do that. So what I'll do is I'll just make each of these a reason like that, right?
So each of these is a reason, if that makes sense. And then I can just style the reasons.
I mean, I shouldn't really have to change any of this, but the nice thing is then I can just style the, you know, I can just say margin-top: 25px here, and then it kind of does this nicely.
So that kind of did the thing that I wanted it to do. Um, so that's cool.
I'll do something like this. I don't want this to wrap, so maybe there's a way to make it so that it— that's kind of nice.
Um, but yeah, anyway.
Um, I can probably do—
how do most people do?
Let's do custom radio button CSS. Awesome. This looks pretty solid.
So let's go with that. It's a little bit more code than I would actually like, to be honest, but that's okay.
We'll go with it.
Um, I also like how it's—
that first one is checked at the beginning. Is that just how you do it like this? Probably won't work for a radio button. Oh, it did. Amazing.
Okay.
Wonderful.
Um, and then the way they did that is they basically just added this check mark afterwards and they'll style, presumably they style the check mark and they hide the native, the native one, right? Normally on Saturdays, I, yeah, we go out. Eat, go to a coffee shop, walk around, go for a hike. Pretty boring.
You know what everyone else does, you know, drive, walk, hike, eat, watch Netflix, et cetera. Um, where did I want to go? Oh yeah, back here.
So the CSS, um, yeah, so you can see it, it hides it and then it creates the custom one. It's a little concerning to me, but whatever.
We'll copy paste and we'll see what happens.
Um, this is a bit aggressive to hide it in my opinion, but it's probably just being overly sensitive, which is okay for a tutorial. And then we're gonna add this custom checkmark.
Actually, let me just copy the whole thing.
Copy. Boom. All right, it's a lot of code. It's a lot of code. We can always clean it up, but, uh, I want, I want them. I want these custom buttons, and that's, uh, the cost of them.
So we'll do it and we'll clean it up later. Oh, it didn't work. Oh no, what's wrong? Try it yourself. Does it work here? Oh, it does. Uh-oh. Okay, well, the good news is that it— where's the gray coming from? So the input—
no, no, what I want is this check mark border color background. So yeah, this should show up.
Okay, this should show up. So why does it not show up? Good question.
Really easy to figure out, uh, which is I just have to go in the code and see, see where it is.
Where the hell did it go? Oh yeah, I could, I could probably just do display flex on, but, uh, whatever. What happens if I do that display flex? I mean, it's slightly better, but, um, I'll do, I'll, I'll, I can update to that at the end. Um, if I need to.
So there's this, then there's this, which is the reason for it might be this position absolute thing.
I think this reason might need a position relative so everything is based off that. And that seems right to me. So let's add relative to it. At least we have that.
And then I'm gonna have to style it.
Um, unfortunately they're not doing that for me. Um, but that's okay because I realized thanks to all you that I can just copy all this and it's super easy. So how, how, uh, what is the width of this actually? Uh, 25.
Oh wow, we agreed. I agreed with them.
Amazing. So let's just do this. And I don't think I need that. And this, I can just do this. And let's see what happens. Okay.
Let's do background white actually.
So it doesn't do, obviously I'll correct this anyway, but might as well fix that.
Um, and then when I do, as I mentioned before, when it's active, when it's hovered over, or no, do I want it to be hover?
Well, we'll see what happens.
Active, I wanna do cursor: pointer, right?
And that didn't work. So yeah, I think it is hover.
Yep.
Cool.
But that doesn't work. It's not actually doing what I want it to do. And the reason for that is because this radio button is not actually in the same place.
So what I need it to do, I believe, I don't know why they did it this way, but I think if you just have it like that, it should work. And let's test to see if these reasons are changing as I click 'em. The way I'll do that is one nice thing about designing in this tiny way is I can kind of just—
wait, how do I do the thing where It adds, oh, here it is.
I'll add it to the right so that, that way I can always have it open. But yeah, you can see when I tap this, it should be changing, you know, the DOM here, right?
Because the checked.
Yeah. See, that's not changing. So that's annoying.
Um, and the reason it's not changing is because it doesn't think I'm actually—
yeah, it doesn't think I'm actually touching the button.
So, oh, and that's where you do cursor pointer. So yeah, you shouldn't actually need this.
I see what it's saying.
Yeah, you shouldn't actually need this, but then why is it setting it to zero?
I don't— that's what I don't understand. Why would I set it to zero on—
oh, Yeah.
Why is it setting to zero height and width container input? Maybe just to do with checkboxes.
I feel like we should keep these. That seems like it makes more sense to me and I actually don't wanna hide them even.
So let's, let me show it first.
Okay.
I'm making progress. I see 'em now. The checking isn't still working and that's okay. That just might be because of the— what I can just do is do a z-index.
I hate z-indexes, so I might clean this up later, but now I put them in front. You can kind of see that they're, they're working, which is good.
Now I just have to make sure that, you know, it looks good. So first off, oh, I have these container things that I don't Probably need—
I don't have these containers, so let me just update these. Uh, I don't— what I need is input checkmark.
What?
Oh yeah.
Yeah. Yeah.
I actually don't want this hover. I think so.
I'll just remove it when— okay, I need this, right? Which is basically when it's checked afterwards, I want the background color to be blue, but I don't want it to be blue. I actually want it to be this kind of cool design that I did, which is basically the same as this.
So I can kind of go back and copy the important bits and just apply them. It should effectively give me that aesthetic.
I don't need the padding, so let's get rid of that.
But boom, now I have that.
Then I can hide this.
Awesome. Cool. Made progress on these nice little buttons.
Um, so I do that when it's checked and then It uses this kind of fancy, it's a little fancy, um, kind of look and feel to do this, these check marks, which I guess is fine. It's a little bit too fancy for me.
So let's just do the boring, easy way, which is I just have a check mark and I just have an SVG check mark and I just have a check. And I just use that and I prefer that. It's a little less hacky to me. It's a lot of code to like make all that stuff, you know, all this stuff. So I think we can just get rid of it. Um, Oh, what happened here?
Oh, weird.
So check, you won't see it because it's white, but in theory it's supposed to be 11 by 8.7. So let's just do that. And then we can, uh, we can deal with centering it in a second. We probably don't need this. So let's go find the check mark.
Oh no, we want the after.
So what I want it to do—
oh yeah, I need to remove these containers.
So basically When it does a checked, it shows it. Otherwise it doesn't show. I see. Okay.
Oh yeah.
Makes sense.
Basically what it's saying is it's hidden by default. Um, and then it's shown, um, when you're, when it's checked. So that makes sense. I think that to test. To make it a little easier to test, I might just change this to block so it shows always, and then I can worry about it. Oh, I mean, I honestly could make it show always because it's white, so you don't really even see it.
Um, but that's cool.
It worked.
It did the— it worked actually faster than I was expecting.
So I don't know why it's so tiny.
Seems smaller.
Yeah, I don't need that. Yeah.
Thanks for those container classes.
Yeah. The one fun part about live streaming is I'm sure that you, you all pick up on stuff sometimes before I do. But I don't know why it's so tiny, even though it seems the same. Oh yeah.
Maybe it's just my perspective on it.
So I'll just center these.
Manually. That looks pretty good.
What do you think?
I think so. Um, and then maybe make it so that these labels, um, you know, have some nice padding left to them. I don't know why it's only applying it to the to the bottom, which is kind of strange to me. Oh yeah, maybe background size. Um, oh yeah. What I also wanna do is I wanna make it so that when these are hovered on, I want them to be—
yep.
Cool.
Awesome.
Yeah, that's kind of interesting that, that padding thing. Um, so yeah, sometimes if I don't know what I'm doing and I don't wanna spend too much like time going back and forth, I'll just do it in here and try to figure out what the answer is.
Um, you know, before I apply it.
Um, so let's figure it out.
Label, what's going on?
Oh, it's display inline. Maybe that's the problem.
What if I make it block? Okay, now I do margin-left 20 pixels. Oh, boom, easy, easy peasy. So make that display block and then do margin-left. What did I do wrong? 50 pixels, just too much. Okay, cool. It's a little ugly still. I would like them to be centered. And why is that?
Okay, so one issue is that line height.
So I want some line height here. Which I don't have. Yeah, it's looking a little better already.
That looks good to me. Um, and then I guess I want to push these down a little bit, right? And those are the check marks and the radio buttons.
So I think the easiest way to do that would best be to add a margin top. Like 5 pixels. Let's see.
Oh, it's not actually what— it might be easier.
No, no, no. 15.
No, because it's position absolute.
Oh, these are invisible anyways. Of course.
So yeah, these are invisible.
I think a better thing to do would be maybe to add like a padding to it to, to offset and then up. Weird.
1 pixel did that.
Very strange.
Uh, what else could I try?
I mean, a kind of a hack would be to just do it here.
Margin top, do like negative 10 pixels.
That's weird.
That's not right. Um, what else can we try?
You can try wrapping the checkboxes inside the label tags.
Yeah, I probably could do that, but I wanna figure out if there's like a simpler solution to get to this.
Uh, I mean, I, I do think the simplest one is to just move the check marks, right?
Just give this like, yeah, exactly. So let's, let's do that.
So yeah, that seems like pretty good, pretty centered, right? You can now select these. This doesn't do anything yet. Padding here is a bit weird, so let's add a little bit more to the— it's a little like, you see how it's a little bit more to the left and the right? I kind of like that. Um, so I'll do that again. This is top and bottom.
This is left and right. So let's add. Yeah, looks a bit better now.
Um, let's add that like icon. So we have this file upload icon, so let's export that as an SVG. Reason to do SVGs for me over PNGs is they just are vectors, so they kind of scale. You don't have to worry about having different files and them getting blurry on certain things.
Um, and Where would I want to do this? Do I want to do it right in here? Um, file. Yeah, probably I could just do icon class, uh, file upload, you know, icon, something like that. I think that makes sense to me.
Um, we'll see.
Um, so yeah, let's do that now. Go into here and then do, you know, file upload icon, and then do this thing background, except this now file upload didn't work yet because maybe this needs some height and some width. Again, I always like to add these to make sure that it's there. Nope, it's not there. Where is it? Let's figure it out.
Oh, display block probably, huh?
Yeah. Or inline block, I should say. And then I probably want him to do a margin right of like 10 pixels or something, right? And that gets that image there. Cool.
Awesome.
What did I do? That was a display inline-block and then a margin-right of 10 pixels.
And then I want the, the, uh, resolution to be better, um, more accurate to what I have, which is 12.5 and 15.
Boom.
It's a little janky, so we can mess with it a bit to try to get it as close to the aesthetic, uh, as we can. And I believe vertical align might be a better way to get that. Nope. That's, uh, middle. Nope. All right. This is the same thing. I go into inspect and then I just go through and I try them all until one works nicer. Than the other, than the others. None of them really look that nice. And the reason is, then I will blame this. So what if I can just do 20, 30, 50?
Um, that looks nicer in a sense.
Line height.
So it doesn't really solve the problem.
That looks, uh, one.
Yeah, that looks good. I think that's fair. I have not yet decided how I'm doing file upload yet. Uh, and then we'll do the address, um, which is going to be—
oh yeah, let's say Stripe Elements has, uh, address. I don't actually know, probably does, but let's see. Are there address?
Awesome.
Let's view the source address. Give me the address.
Address outside of the—
okay, so it does outside. Well, good to know. Let's see, where does it do it? No, it just does it here. So let's go into the index example 2. Oh, so it just does it. It kind of just does it, I guess, huh? It's not really using—
uh, that's annoying.
Um, oh, whatever, not a big deal.
We'll just make our own little thing. Um, pretty easy to do. I'm gonna have placeholders for these.
Right, placeholder equals apartment number. I'll copy that.
This will probably want to be a select.
Um, actually, no, uh, because it will make it easy for folks who may not have in the US. But this select, I think, will want to be, you know, and we can worry about getting them all later. So let's go back.
It's not the end of the world.
I mean, it's not terrible, but I think pretty quickly we can make it a lot nicer. So might as well, right? Um, so what I can do here is I'll make this input type select. No, just select. Uh, boom.
Now that looks kind of similar. It's a little bit janky.
You can kind of tell.
Um, So probably need to tweak adding on selects specifically is a little different.
I don't know exactly why. It's kind of ugly to me. But why is it slightly different? That's weird.
OK, now that matches. This thing is still strange. I think the easiest way to fix that is just to do appearance none.
And then, then you can have your own. Cool.
And now what I can do is I can just take this little—
might as well use this, uh, I don't know why I'm— let me lock this. Why can't I grab it?
Weird.
Not a big deal. I'll just go find the address box.
Oh, it's locked.
That's why.
Cool. So I'll just take these arrows, same thing.
I'll make this an SVG and I'll find another reference to an SVG so I can copy it super easily.
And then, you know, it's arrows. And then what I wanna do is make it basically middle, center, right, center, right, something like that.
I forget exactly what the, what it's gonna be. But that's okay.
Definitely not what I typed, I guess.
Oh, let's get rid of that. How do I do like, Um, uh, center, center does it right in the center. And now I want right center. What if I want 10px? Negative 100 pixels, right?
Oh yes, sweet.
That worked brilliant.
So what is it?
It's right in center, something like that. Boom. Lovely.
And then finally we can just clean these things up, uh, to make it look like my form, even though I don't know if I'll end up that way, but we can do it. Um, And I probably don't need all of these, but let me just add them so it's easy for me to add custom styling to them.
And I'll just add country here. Good practice.
Nothing should really change because of that, but at least now these are all tagged. The nice thing there is I can kind of go into this and say, hey, you know, if any of these inputs are some of these classes, we wanna make them look a little bit differently, right? Like, for example, we don't want the margins in between them, right? And we kind of want them— I'm doing this thing where they're kind of next to each other and things like that.
I don't know if I'll stick to all of this, but a simple way to start would be to take all but the top, which is apartment number, city, state, zip code and country, say margin-top is not 25 pixels, actually 0, right?
Boom.
But that's not enough because you have these little weird things right happening here. So what you also need to do is you got to remove the borders from the top of them.
So border-top-left, you want to make 0, and border-top-right You also want to make 0. Yeah, I guess it kind of works. The problem is you want to make street address the opposite, which is you want to remove the bottom of each of these. And on all of these, actually, yeah, you kind of want to— It's a little janky, but what you really want to do is—
and then on country, you actually want to add it back. Again, the goal is to make it so that this works.
I'm not trying to pretend that my code is super pretty.
But even if you go to that Stripe example, for example, it's not the prettiest code on planet Earth. And then last thing, I want to remove the border. Right? Because you can have this doubling up of borders.
So boom, now you have this nice thing.
Um, looks pretty cool. You have everything in a nice thing. You could probably do a little bit more here, right? Like I'm, I had, um, like what does that Stripe example look like?
They probably have some good ba— best practices on, on what it looks like.
So they have street address, they don't have apartment number.
I do think it is kind of important. Don't worry, I don't live there anymore.
Um, but I do like how they have city, state, and zip next to each other. Um, so I want to do that, uh, city, state, and zip. Uh, and I also do wanna combine these. So what I can do is I can just say div class, uh, grouped inputs or something like that. And then I'll use flexbox on these.
I'm sure people watching want me to do that. So let me do it.
So I have these grouped in, but they shouldn't have any effect right now. I've just— there's no real style change. But now that I have grouped inputs, what I should be able to do in theory is make these flexible. Boom. I do have to rewrite some of the code, but, uh, it's getting there.
It's getting there.
Um, and let me update this. So now it's a little bit different. What I have to change, there's a few things I'm gonna have to do differently, but one thing is in all the grouped inputs, the basically, you know, it's kind of like what I did here, like removing the top and I have to do the same thing, but now left and right. Right. Because The first, uh, you know, basically the everything except the first child, the first element, you're gonna wanna remove the border-left with, I don't even know, but let's, let's, I'm sure I could think about it more, but it's even faster to just test it and see if I did it. Actually, no, you're right.
I want, I want this.
I want, I want the left width, uh, to be zero because I want it here. I don't want it there and I don't want it there. And I want the right on all of them.
Yeah. Cool.
So for some reason that's not working.
That's okay. I'll figure that out.
Um, street address, all of a sudden I might actually have to change this to, um, No, first row. I don't really like that.
I wish there was a better, whatever.
For now, I think it's fine to just change this to first row. Um, the other thing all of them need to do except for the first is their border top left radius has to be zero.
Right? Like you don't want that to be, um, anything.
And then you actually wanna change this so that all of a sudden it's the second row and country.
Uh, I want that.
Getting somewhere kind of second row. I don't know why there's margin here.
This actually looks kind of cool. Like maybe we just do it this way.
Um, we'll see. I don't know where this margin is coming from. Margin top.
All right.
So Yeah. Any inputs in that, I just do margin-top: 0. Didn't work for some reason. I don't like doing this normally, but let's see what happens. Nope. Didn't fix it. Let's see why not. Does anyone have an answer for me in the chat?
Nope.
My tech support's not there for me right now. Well, this is nothing and then these still have it. And the reason is these are type texts. So I might need to specify, this is, it is, oh no.
It's, oh yeah. It's not the grouped inputs.
It's their children's inputs. So what it is, is the inputs that are not that.
Yeah.
See, now that cleaned it up nicely. I kind of need to do the same thing on the opposite side for the last child where it's about the right, I believe.
Like that.
Uh, kind of. All right, we're getting there. Oh yeah. And then bottom. So I'll have to tweak this.
Um, but we're getting, we're getting close. We're getting close.
Um, actually the top one looks nice now. I'm still not sure why this is not getting hit by that, uh, this thing that I added here.
And the reason is this is under— oh, this is under the input.
Yeah.
Oh, so this is—
this shouldn't even work. Why is it second row input? Yeah, this should not work. Because I moved them. Yeah. So I don't think any of this works actually.
Um, yeah.
So let me move 'em down here and then remove these ands. All right.
Getting somewhere.
Cool. So second row and country.
Yeah.
See this? Yeah.
What I wanna do is I want the inputs to be like that.
That's what I want.
Yeah.
There's still a bu— there's some issue here because there's no, there's like a padding missing.
So instead of—
maybe I can keep the, the left and right padding and just make the color white, which might, yeah, fix that issue.
It's a little janky.
You have this like slight edge there that you can kind of tell what's happening. But that's okay for now.
And then the first—
and then what I, the other thing I need is I need the first row input. So the first row inputs. Boom, like that.
And that's pretty close. I mean, that's pretty close to the design, I think. I mean, I could get rid of the lines, but I actually kind of like them.
This is one issue you have with that Focus now is that they're all effed up because of all the borders are all janky.
There are ways to fix that. I could do it differently. I think the simplest solution will be—
I mean, how effed up is this? It's not ideal, but it's not bad.
I think the simplest thing to do would be to basically just take all the grouped inputs, and whenever they are focused, don't do the border. Just do the same normal whatever.
Border color, kind of border width 1 pixel and border color, etc. Why is that color wrong? What is, uh, I could use variables, but See, you're seeing that. You see that? Kind of weird, right? And the reason is that the group inputs— yeah, OK. I see why it would do that.
Well, one option would be to remove this.
What happens then? It just bolds it. I don't really like it. I think it's a little weird in this context. So maybe let's just change it all over for one. So, and then it's just one and then it's a little less weird.
Still a little weird.
Still don't really like it.
Um, yeah, I don't really like it. I think what I'm gonna do is just change the color. Then whatever the color happens to be, it'll just change the color. Not perfect, it still does these double lines.
Um, but it's kind of hard.
So anyway, that's fine. I'm pretty happy with that as like an MVP. So almost have like the whole layout kind of done. Um, oh, payment info, that's important.
Stripe Elements. Um, let's do it. Um, try it out, explore the docs. And the one I want is something like this, I guess. Um, so let's figure this out. Um, but which, which, uh, one, which example is that? That was, uh, it doesn't say. 1, 2, 3, 4. Cool. Before, there's some feedback where Stripe can improve their UX. Who would have thought?
Uses payment request button as well as card element with the custom web font.
Cool.
Oh, uses Inter, nice.
Alright, am I ready to write some JavaScript?
Why not? I haven't written JavaScript in a long time, so it might be a little rough. I might have to Google Stripe Elements Rails example. I don't want this to be a video. Oh, it's a video. Oh well, I'll figure it out. Oh yeah, this is a good, uh, tutorial. All right, cool. Thank you.
So we can go to the index.
We can just add this Stripe somewhere in there to the head of your HTML file. All right, let's do that ahead.
This means it'll be included on every page, but that's fine for now. Um, I'll use the Gumroad key.
I'll change it later. Um, And then my guess is probably in here. I'll just have a script. I don't see why not. Do I have to do type text/javascript, something like that?
Is it?
Probably not even needed anymore, but whatever. All right, so I have that. I could use even Stripe Checkout, to be honest, and that would simplify it even more. But anyway, I kind of like the, the, the example. Oh, I have to verify my domain with Apple Pay. I wanted to have to do that later. Oh, I guess I could just do it there. Cool, good to know. All right.
Oh really, I can just do it all within there.
Okay, yeah, well then I don't need this here. Cool, I can just do it all right there.
Hey, Data Salaryman, I'm great at this. Um, I think it's not about you're not great at this, it's just this is what great looks like. No one, no one doesn't do any, you know, the best engineers I've ever worked with do exactly this.
Like, it's not like, you know, uh, it's just part of the process.
You think an architect just like builds a house like without referencing Google, or doctors use Google all the time.
Like, we all Google. It's essential. It's the way it goes. I'd probably be a little bit faster maybe if I was doing it without being washed, but not too much faster. So I got that, and then I'll move— I'll keep that there. That seems fine for now. I'm just going to make it so that this payment request is going to be— what is it— $25.
Um, total label, sure, feels reasonable to me.
Create and mount. So wait, I type var parent. Okay, then I just do this.
The most important part is that you actually build stuff.
Like, it doesn't matter how much time you spend with your head against the wall.
All right.
This is server logic, so I can kind of avoid this for now.
Um, but let's see if I can at least get like a the stuff to show up so that it feels, you know, that stuff's happening. There's some Stripe stuff happening. Payment request button is none for now.
Yeah, it doesn't get any better than this, sorry to say.
This is it. This is the peak. Um, yeah, I don't know exactly why the Stripe docs are not as nice everyone says they are, I feel like. But whatever, I'll just copy this and we can mess around. Otherwise, I might just use Stripe Checkout, honestly, to simplify my life a little bit more, make this even easier to ship an MVP. Hmm, can I see an example? It would be really nice if they— see, like, what I don't get is it says mount create. Is this— did I create this? Yeah, so I did. There should be there. Yeah, Carlos, I agree.
That's why I'm kind of doing this, just showing people that this is like what it is.
Like, there's nothing— I, I used to, when I was in school, I used to think that like people would like have supercomputers like to build Facebook or something, you know, not just like Nope, just a bunch of people on their laptops building stuff, nothing too crazy.
See, this is what I want. I want this awesome example, um, just to work. This is, I guess, why they want more people to use Stripe Checkout.
It's actually quite a lot of— quite confusing.
Maybe it's because I haven't verified the domain.
Uh, shouldn't matter.
Oh yeah, maybe I'll just do it without Apple Pay for now.
Let me just do it without Apple Pay. Let's just do Stripe Elements normally. Um, Okay, setting up the payment element. Add payment.
What?
Yeah, see, I am doing that elements.create, but I don't wanna be creating the payment request instead. What the hell are these built in? No way, really? Huh, that's funny. Um, cool.
Yeah, I guess I'll use this.
I mean, if it works, we'll try it out. It's beta. Can I use it? Function. No, this looks like a React example. Hmm. Hmm. Maybe I will use Stripe Checkout. Yeah, let's do that.
Let's simplify things a little bit more.
I don't wanna spend too much time. I'm at 1:00 PM.
Cool.
There's some more no-code happening.
Well, The good news is I could do proceed to payment, uh, right here.
And the way that this will work is basically, and I will update my Notion, is this homepage will basically redirect, do this function, which is in the backend. So this is like frontend, right? Then this is backend. The backend is gonna get hit. It's gonna save all that information to the database, and then it's gonna redirect to Stripe. Um, and then it's, once it gets back from Stripe, it's going to add it to the queue and then redirect to back to the frontend, which is what the user will see, which is the web receipt page. And really quickly, what I can do is I'll just use the welcome controller. I'll just make a thanks page here.
So what I can do is literally just copy this and do thanks.html.erb. Find the kind of thank you page, which I'll just copy paste with its text. There's not gonna be a form here, so let's just delete the form. Let's make sure that it says this instead. Oh my gosh. You're all set. Expect an email from us within 24 hours, etc. That's bold and that's black. So let's do that. I know we normally don't do this, but just to finish up before I take a break, I'll do this. Um, and then in the welcome controller, it won't actually be anything there. I think this is— oh no, what I need is in the routes route. I'll say you go to /thanks. And you're gonna be sent to, uh, welcome. Uh, but it's gonna be the thanks.
I don't even know if I typed that correctly.
Oh, obviously did not. Good to know. Not a big deal.
Could you be more specific about front end dev? What, like, what do you, what are you trying to build? Always start with what do you want to build first.
All right.
So what if I go to thanks? What happens?
All right, this is a little janky. Um, so let's fix that up.
And the way you fix it up is by going to the paragraphs and adding line height. Um, and then this, uh, what I need to do here is Um, let's reorganize this a bit.
The reason is I had this janky thing, so it kind of assumes, right, that height, as I mentioned. So I think if I just want min height, it'll fix it.
Awesome.
So now you have the thanks, you have this page. Uh, one small thing I can do to make it slightly more efficient is auto focus.
This one.
So when you go to this page, it's automatically selected.
You can start typing.
Um, I haven't done the upload docs stuff. I'll do that.
This, you know, pretty small thing I'll probably want to do is change this to, to email, which loses that styling. So I have to go back. This, and that should come back. Boom.
Proceed to payment.
This should work. Awesome.
So we have like, you know, we have kind of like the, the skeleton. Still more to do, of course. Um, but we've made good progress.
So let's push and I'm just gonna run that command. That kind of does everything.
And I believe because it's set up to deploy automatically from—
it should in theory— oh, JK, it's not actually set up anymore because it's a new thing. So let's do that and let's see if it'll work. Um, oh yeah, let me— and then do git push heroku.
I mean, most people stare at their computer all day every day, to be honest. So no, no, I don't really get tired. I get tired of other things, but my eyes, no, not really.
You're staring at something no matter what.
Mm, while that's happening, might be good for me to create a new Stripe account. I'll probably activate it without sharing my screen because it'll probably ask me for some personal information, but What I'll do is, you know, there's kind of two tiers, right? There's the $25 accredited investor tier and the $50 qualified person tier. So I'll just say accreditation or accredited investor verification.
I'll—
we can all fill that in if we feel like, but that's $25.
It's one-off.
And oh, I can do other prices. So I could even have— what I could do is a verification Uh, and then I could have another price and I could say it's 50. And I can give this price description, which is accredited investor verification, and then this other one, which is, um, qualified purchaser verification. Save that. Now I have a verification product. I have these API kind of IDs. I can have payment links attached to each one of these. Um, so actually the easiest thing to probably do would be to literally say create payment link.
Um, oh, I could even get Stripe to collect the billing address.
Mm.
Let's keep it simple for now. And then this is going to redirect people ideally to the website. I'm gonna have to figure out how to show the proper thing.
I don't know, maybe we don't even need it. Maybe this is enough.
What if I add this? What's the default? A payment will appear on—
yeah, I guess I could probably just do this, like, to keep it super simple. Just like take this, um, and say something like that.
And hit create link, I guess.
And I will literally, actually, no, I'll do, I'll do that in a sec.
But what I will do is probably create a checkout controller or something like that. Um, which if I still in my history. Um, I forgot how to do that.
Um, but anyway, if you go to verificationletters.com, I think you should see—
oh, there's no image.
The images are gone. Why?
Good question. Probably forgot to upload them.
Yep.
So now I have up, I've added them and I'll do the same thing that I do.
I'll push to GitHub and ideally now we can test actually if the deployments are automated. So we'll see shortly.
I will connect Supabase soon and that'll be kind of like the next big thing that I do.
Let's close some tabs that I no longer need. Um, so yeah, let me, let me see if I can create a checkout controller. Rails new, is it? No, that's like the OG new, new controller. Generate controller.
Yes, great, great, great.
So what I will do is rails generate controller and I'm gonna call it— this is a good question— which I'm gonna call them verifications.
That's kind of what this is about, it's verifications. So I'm gonna call 'em verifications and I'm gonna do, I don't know, hello, I guess is kind of the first method.
And so in this case, it'll be, you know, checkout, right? Kind of thing like submit.
Actually, I'll do that. Submit is kind of, cuz that's like kind of what I think is happening is like they're submitting the form, right?
Initially. So let's go with that.
Okay, so now we have a verification controller. The reason I wanted to create this, um, is just so I can honestly have this link saved here. Um, and let me create the other one.
Might as well do that.
Um, let's create a new payment link.
It's a qualified purchaser.
Kind of same ordeal here.
We're going to take this and we're just going to simplify it. We're going to take a create_link. I'm going to copy it.
And then the pseudocode is going to be something like save you know, information into a new DB record, right? Like create a new verification record.
If, you know, verification.type equals equals accredited investor instead of qualified, you know, redirect here. Other else, redirect to here, right?
And then there will ultimately be, you know, kind of like a listen to Stripe kind of webhook, you know, that like listen for payment to make sure that, you know, once the payment happens, it kind of triggers like, you know, add to queue, maybe, you know, send email to CPA, right? Something like that.
So I will keep these.
I mean, arguably Stripe is kind of done cuz we decided to go with, uh, with Stripe checkout. Um, I will have to integrate, but I'll kind of do that in the backend step. The frontend is kind of done. There's the form that exists. We haven't done upload yet. Um, so I think that's the next thing I'll do is kind of get these entries saved to the database. I probably won't do Stripe immediately. I'll make it so that you can save entries to the database, um, and they're probably auto-added to the queue. WebRTC I actually don't need either now because we're using, uh, we're doing Stripe as well for that. Dashboard, honestly, this should be pretty easy. I think the hardest thing here will be generating that PDF. And sending the email.
It should be pretty easy using SendGrid or something.
This, we'll see. It's 1:00 PM on Saturday. Um, but I think I'm making good progress.
I think I have, uh, I'm making good progress. So we'll see. We'll see how, we'll see how I go.
Anyway, I'm gonna take a little bit of a break. It's 1:00 PM. Um, so I've been going for 3 hours. So this is about 3 hours of work. You can go to verificationletters.com and see it.
And hopefully there are images there if I got the deployment working properly. Uh, no, I did not. Um, why is deploy not set up properly? It is set up properly.
Hmm.
Let's figure that out. I did deploy. I did push 5 minutes ago to master. Hmm, weird.
Oh, it's not enabled.
Duh, duh. All right, well, I'll just do this manually then and we'll see if it fixes things.
Let's see. Super base.
So let's go back to verificationletters.com. And the deploy is still happening.
Um, sorry, I thought that was going to be a little bit faster than it was. It's compressing. I guess we're uploading these images.
So it's a little bit slower. All right, almost done launching. Oh, not yet.
Where are my darn images? All right, wait, let me— I'll share my screen and debug this. Together and then I'm gonna, I'll take a break after this.
So yeah, why are there no images? That's weird. I deployed them. It might be that like the pre-compile, like the compiling step on Heroku is, is not exactly what it should be. It might also have to do with this HTTP thing.
Nope, that's—
this seems fine.
Images—
no, because on this, on local, it is going to be different. Yeah, see, it does the proper compiling there, but okay. Heroku images are Oh no, this seems like pretty complicated stuff. All right, let's see if this seems— assets.compile is false. Let's make it true. What about digest? That's not even there. Let's make that true as well. And if you have syntax like this, which I believe we don't— I believe we do use image. Yeah, we do. All right, so let's do that, see what happens.
And now it should be the auto deploy thing happening.
So let's go back to Heroku. Build in progress. You can view it here. Let's see if that fixes it.
There's— it probably won't, to be honest.
That would be pretty easy. But this is where I want to include the Oh, maybe it should be asset URL. I might have to— uh, no, I don't think so. All right, let's see what happens. This is live.
Yes.
All right, all right, still didn't fix it. Yeah, it's not doing that properly. Super weird. I'm not sure exactly what's going on. And yeah, maybe asset URL. I have noticed sometimes that's better than image URL for some reason, so we might as well try it.
It's annoying because it works locally.
Asset. All right.
So that still works locally. Um, yeah, so might as well see what happens. Yes, I know I set it to true. Yes, it's probably bad. I will undo it. But I won't push that. So I wanna see if I fixed it with these existing changes. If not, it's okay.
I'll take a break probably until 2.
Um, and then come back and keep going.
Keep cranking on this until 5. There's another 3 hours. You know what you can do in 3 hours?
Freaking everything.
Yeah, the paths are different in the production build. There's no— they just use the default, like they don't, you know, just /images/logo, which seems off to me.
Um, Yeah.
Oh, something seems to be maybe happening. I don't know.
Yeah. See, look, it doesn't, it's not compiling the images.
It seems like I don't see any of the images showing up. Uh, so yeah, I'm not sure, but whatever. I'll figure it out. We'll figure it out. We got time. We got time.
Otherwise I can like upload them to AWS in some bucket and just link them or something, you know?
Um, oh, it worked. Awesome.
Boom.
I wanna do something cool here where I can make it so that it just keeps showing even as you scroll, but boom, look, you got a page, everybody. Um, this won't do anything, I guess, but if you go to thanks, I guess we won't be using thanks, but that also exists. But yeah, I mean, we have, I mean, we're making good progress. I think, you know, it's not done. Um, but we have kind of like some UX, um, to a customer, it's gonna feel pretty real pretty quickly. And you know, the cool thing about all the dashboard stuff that we are gonna do, right. It's like, yes, we definitely wanna do all of this, but in theory it's not super necessary.
Right.
You could, you could manually do a lot of this stuff. Right. Um, I'm sure if I gave my mom, for example, access to Supabase, like she would be able to come in here, you know, let me just make a verification. Um, you know, and ID created at, that makes sense to me. I'll fill this in later, but you know, I, I assume they have UI that she can kind of come in and just do some of this, uh, work herself. Um, so in theory we don't need all this. I'm gonna try to do all of it. By Sunday night, but I think we're making good progress. So yeah, I'm gonna take a break for like 30, 40 minutes. And then I will start on trying to finish up. I, my hope is by the end of today we can do all of this except for maybe the email with the download link for the PDF.
Mostly the PDF thing is gonna be a little tricky.
And then maybe even Maybe I can start out, you know, designing this, implementing it in CSS should be really, really fast. So hopefully that was helpful. Hopefully it's been useful. I will just stop sharing my screen and turn off video and audio and I'll just come back in 40 minutes.
All right, I'm back, I'm back, let's go!
Just wanted to give everyone a cool update on The Minimalist Entrepreneur. It's doing really well.
Oh, I'm not actually sharing my screen, sorry.
Um, yeah, we're doing well. It's, uh, $11,000, I guess. I don't know, that seems not well, I guess, but I guess in the categories, uh, that we that the book is in, it's pretty good. Starting a Business, you know, we're top 3, not bad for a book that hasn't come out yet. So thanks for everyone who's pre-ordered it. I do appreciate it. Whether you do it from Amazon or my own website or anywhere else, very, very appreciative. So yeah, let's get back into it. So as I mentioned, we're going to We've kind of finished like the rough front end homepage bit and the sort of overall design aesthetic. So I think, you know, not too bad for like 3 hours. We have another sort of 3 or 4 hours to go today, probably 3 hours to go today, and then tomorrow might be a little bit of a sprint. We'll see another 3 to 6 hours, probably another 6 hours or so tomorrow, and I think that should be enough. But, uh, might be a late night.
We'll see.
We'll see what happens. Um, I'll have to look at my calendar on Monday morning. Um, or put in some late, late time, uh, late nighttime, uh, today as well.
So we'll see.
Um, but anyway, let's get started. And the way where I wanna go next is actually start doing kind of the, the backend, actually uploading documents, like all, all that kind of stuff. Um, and I thought I would use Supabase, uh, for it. Um, so yeah, let's kick that back up. I never used Superbase before, to be honest. Um, so I might give up. Um, but let's give it a shot. And so what, what do verifications need, right? So, uh, you know, there's gonna be a, a table and we can just like kind of scope this out. Um, schema and there's gonna be verifications, right? And each verification has these things, right? ID created at kind of standard stuff. Um, you know, the ID. Increments one by one, and then this is kind of the timestamp of whenever the record was created. And if you go kind of, you know, I use the design to kind of remind me of what's actually going down, right? You're going to need all of these inputs that they've entered saved, right? You need their name, their address, verification reason, supporting documents, et cetera, et cetera.
So Yeah, I think it would be good to, uh, to do that.
So email address is probably kind of an easy one.
Uh, we're no longer doing payment info, so maybe it's worth kind of updating this to remove the payment info from our designs. And is it anywhere else? Not there. Awesome. Cool.
So email address, full name.
Should I do full name or legal name? Let's do legal name just to match the things.
And then I would say street address, apartment number, city, state, zip code.
Country, verification reason.
This is going to be, and then supporting documents, which I think will be another table.
And email address I already have at the top.
That's kind of the most important thing. I might actually move, even in this design, it might make sense to potentially move email up is what I'm thinking, right? That you'd think that that email would kind of go ahead.
Ahead of, you know, like here, right? That seems like it makes sense.
For some reason I like legal name first.
For some reason, maybe it makes—
maybe here.
Um, I don't know.
Well, for now we'll keep it here. We can, we can mess around, or maybe, maybe we don't even need this because if Stripe Checkout is doing that for us, right? Um, we might not even actually need it. Um, So let's check actually, do we need it? Let's simplify things for us.
Um, I mean, we probably do wanna, hmm. Yeah. Hmm.
Yeah.
Let's keep it for now.
Let's, we can always simplify things later. Um, so cool. Let's, let's get all this stuff into this, into this table on Supabase. Um, so email address.
Um, and that's going to be, oh, user-defined enumerated types. Why can't I select something like string or something like that? Oh, it can be a variable length multidimensional array. That's pretty crazy. Import data via spreadsheet. Well, all sorts of crazy stuff. Foreign keys. No, I don't want foreign keys.
Um, I am confused at why I can't change this. Does anyone know why I can't change, uh, Supabase can't change, uh, column type?
I am in the table editor. Let's remove that. Start again, again, one more time. Timestamp TZ, add column. Why can't I select that? Weird.
I don't know.
We can always try it and see what happens. Let's just add these.
Email address, legal name.
Street address, part number, city, state, zip code, country, verification reason, and supporting documents, I guess. Supporting documents. And this is actually going to be Uh, another table that I'll create later.
Um, default values can be null. Okay, see, now they're showing up.
Interesting. See, this is why you just gotta keep going sometimes. It's gonna be text. It's gonna be text. It's gonna be text. Let me guess, this is gonna be— I don't know what the difference is here, but let's say go with text. I think one supports like longer strings or something like that. Text, zip code, text, country, text, verification reason. Ooh, this is a good point.
This might be enumerated. Um, let me go with int. Because I'll basically just do 0, 1, and 2, I think, for the reasons.
I think that's simplest. And this will be, as I mentioned, it's going to be—
oh, yeah, let me add a credit qualified purchaser.
Qualified. That's going to be a Boolean. And the default's no supporting documents. Let's just keep that. Let's save. Ensure that all— okay, so I have to pick a type. Um, well, let's just remove this for now then. That's— we can always add it later.
We'll do file uploads last.
How about that?
That way we can do the form and then we can do we can actually do saving to the database and then finally we can do uploading, um, as like a next kind of step.
Um, actually let's just, yeah, yeah, yeah, yeah.
Let's, uh, let's consider this frontend done.
Sorry, I'm a little bit anal about my Notion usage trying to make everything pretty. Did this save? No, it didn't because I don't have a name. Verifications. All right, we're creating a table.
And the reason I'm using Supabase instead of just Heroku is cuz I've had bad experiences with Heroku's database stuff in the past and I want to try Supabase. Um, and especially file uploads, I've heard better for that.
So, uh, hopefully that ends up being true.
So it looks like I have a table. I'm gonna create another table, which is supporting documents, right? And similar thing, this is going to basically be, um, file uploads to Supabase.
Let's make sure I'm doing stuff correctly.
See, so the way it works is it uploads to It uploads to a bucket, which is fine, but my guess is it's actually not part of the database. So then what I might actually do instead is get rid of this table.
We don't need it.
Go back to verifications, edit the table, and then go back to these supporting documents that I never ended up adding.
And just making this an array, as I, as I saw, it was an example of, wasn't it? I feel like I saw, I saw one that was kind of like an array. Uh, maybe I'm lying to myself. Uh, JSON's pretty good, which is probably what I'll end up using unless there's other ones hidden. Nope. Okay, cool. Yeah, let's go with JSON for now and that'll just be basically an array of, you know, uh, your URLs of the files and the, you know, whatever the storage is. So now that exists. Um, should I enable RLS? I don't even know what that is. Row-level security. Sure, let's do it. Might as well.
They use a color that makes me think I should have turned that on. So cool. I have this now, which is awesome. I can insert rows, I guess, manually.
But oh, that was actually kind of cool. You can view data.
Oh, interesting.
Okay. Yeah. Makes sense.
So I, well, I don't want to do it here, right? Though it is kind of cool. Instead, I think what would be better is, oh, and here's the storage, right? So, okay, let me create a new bucket.
So, oh, can only be lowercase.
Supporting documents.
Boom. I have things I can upload here. That's cool.
I can have policies.
Oh, that's cool. Awesome. That's nice. Add column, add comments. That's cool. This, yeah, it's a pretty cool service. I think, I think it has potential.
So authentication, I'll probably do something.
I'll do this later, but once we do get to the admin side, I might use this as well and we'll see how that goes.
So yeah.
Okay. So we have this. Let's figure out how to actually use the API to send information to it.
And I would prefer to use jQuery, to be honest. Like I would love to not have to use one of the frameworks.
Just cuz I feel like it would be, it's a pretty simple app. I don't know if it requires so much of that. Um, alright. Tables, verifications.
Oh, what? Cool.
Interesting. No, I just wanna insert rows. Yeah, exactly.
That's what I wanna do. Right? So basically this insert row does this, but it looks like it doesn't in JavaScript.
That's all I want. So I wanna do insert row into Supabase Rails. I mean, yep, this is correct, but again, I need, I don't want JavaScript. I need a non-JavaScript example. Maybe I can't use Supabase after all. Hmm. Array was in the settings button. Okay, I'll go, uh, sure, I'll go back and see. Table verifications. Where was it? It was in settings, you said?
Oh, define as array.
Very— I don't really know what this means. Variable length, multi—
Dimensional array.
And then I kind of want it to be text then, right? Because then I want it to be a bunch of URLs.
Is that right?
No.
Okay, let me just cancel it.
Um, we'll keep it, we'll keep it like that for now.
We, we'll mess around with that later.
Um, Okay.
I might not be able to use Supabase if it's only JavaScript.
That's kind of annoying. Supabase Rails Ruby. I did see this, but there's like no README, which is a little concerning to me that there's not none of this here. I'm sure it works. Uh, do they have specs? Nope. Makes me feel like I should not use this. There's also this Postgres thing, whatever this is, isometric. Um, oh, there is some code here. What is this? Oh, it's for Postgres. So yeah, maybe I'll just go with, with Heroku.
I've done that before. So we'll start there and we can, uh, we can, uh, figure it out. So That means I'm gonna have to run a migration locally.
So let's do that. Rails run create:need. And the way I can do that is take this and Say add verification. Now we have this nice little thing.
And then we can add— wait, what about adding the table initially?
Yes, this is what I need.
Create table verifications.
Create products is probably what I should have— create verifications is probably what I should call it, but it's OK. And then I'm going to take this list that I nicely made and string or text.
Nothing is really text needed, so let's just do them all as strings.
So I can just take this. Draw a long line down here. I could just do that.
And this is not ideal for everything.
I would say it's verification reason, probably shouldn't be a string. It should probably be an integer. So let's change that.
As I mentioned before, it's going to be like 0, 1, or 2 for those two.
There's 3 different options.
And supporting documents is going to be another table. So I can worry about that later.
Let's just work on this for now. So now let's run it, which I believe is like migrate is the function. So let's do it. Let's see what happens.
It's all local again, right?
So, oh, I already, I defined, I shouldn't do created_at. That's already a thing.
Oh, legal_name is what I needed.
Why did I type name? Legal name. Is that right? Did I get everything else? I think I did. OK, cool. So let's do that. Try again. No, didn't work. Oh no.
It's because some of it ran probably.
Now it's in a weird state, huh? Well, an easy way to check is to go to schema. Where's the schema? There's no schema.
You can't define an already defined column legal name.
Oh, duh.
All right, try again. Okay, awesome.
So I now have, uh, verifications. Sweet. Um, and how do we check that?
We can open a new one and we could say, oh no, that's not what I wanna do. I wanna, oh no. Wanted any one of these.
Yep. And then for this one I can do, was it bin/rails db?
Something like that. Oh no, I don't actually know how to use this. Let me just exit. I can do console though.
And then I can just do verifications.all.
Uh, I should have— hmm, that's weird. I should feel like it's not what you have to do.
Verification.
Is that not right? What's this? I don't think that's a thing, is it? Weird, weird. Did I create a verification thing?
Oh, I guess I did, because when I created the verification—
okay, yeah, interesting. Um, Interesting, interesting, interesting. Well, at least now we have a schema, so this should show that we have a table and it has legal name, all that stuff.
Oh, integer.
No, fuck. Why did it do it that way? T— oh, I'm an idiot. Uh, no, this is gonna be like, okay, well I'm gonna have to create a new, new migration to fix that. Not a big deal. Um, so let me fix that, which will be something like this. Oh no, that's a bit too fancy for me. Where's the example that I need? There, let's find it over here. Changing columns. No, I want the generator example. No, maybe it's not worth it. Maybe I should just do it and then I can worry about, uh, generating it later. Uh, yeah, I'll just do that. Whatever. So I'll go here and I'll just I'll just say generate migration and I'm going to say create— oh, sorry, update verification reason. Right, and then I'm going to click here and I'm going to change— this is going to change by going back to where it was before, where I was before, which was changing the column. Table name, column name, and then change the type. All right, cool. Sure, simple enough. This is verifications. Part number is going to be— what did I call it?
I called it integer, so I'm going to have to rename it.
And I don't know if I can even do that in the same migration, so I'm going to rename it from integer to verification. Oh, fuck, wait, can I not?
Oh yeah, you know what I should do? Actually, I'll remove integer. I'll remove integer and then I'll add.
Yeah, that's easier. Then I can just add and remove. Yeah, I know I could roll it back, but, um, I don't know, scares me. So I'll just do the— I'll just do this. Where's remove column? Remove column. I don't know why you need string there for remove_column, but whatever. Remove_column from verifications, which is called, uh, integer, and add, and it is a string, so I'll just keep it there, I guess. And then I want to add a column, which is verification receipt. And I think that should do it.
So once I— oh yeah, this would do it for me.
I'm an idiot. If I just did it like this first, huh? Hmm. That would've been better, huh?
Hmm. Should I do that?
Eh, whatever. I made it this far. Let's see what happens if I run this.
All right.
Now check the schema.
Boom.
You have verification reason.
And so yeah, that seems like everything we would need. And now let me generate the model.
This might cause some issues because it's going to have that migration potentially, but let's see what happens. Yeah, I probably don't want to do this actually. I'll just create this manually. Not a big deal.
Touch.
And yeah, that's basically all I would need, I think.
And then this should soon start working if we fill it up. Where is the model?
Like, what's an example of a blank model? Uh, where's the model? There's no model, uh, example. Weird. Hmm, don't you need like a model file?
I mean, I guess it's generated, so in theory you don't, but, um I feel like it would be a good idea.
Let me just look up an example, see if there is one. App, models, and then, you know, post or whatever. So let's just do verification.rb should now exist in the model.
This can just be verification and then we can not have to worry about anything yet.
Yeah, so let's see, let's see if now we go back to the database and we do verification at all. There's none, right? Boom, that's what we want.
Um, so that's great. And so now what I think we can do is Uh, save all this, you know, create a new record. So let's go into VerificationsController, and boom, right here is my pseudocode that I need to make real code, real code now, which should not be very difficult because they gave a bunch of examples right here.
So it should be pretty easy to do this kind of stuff.
And if you go to the CRUD app You'll see the creation right there.
Boom.
So you have all the, you know, all the things. And what I think, you know, will probably— I will need is some sort of index, right? Where, you know, probably a dashboard, um, that you'll be able to see.
And I'm gonna make a route for that, you know, get dashboard to Verifications dashboard, right?
Um, and then I'm going to add a POST, um, the submit verification, and that's going to send to verifications, verifications, uh, submit, I think it was.
All right.
Yeah.
Cool. So that, those will be the kind of the new routes. Um, and then we can kind of work on this. So what we want to do here is we wanna take a verification, we wanna create one, right? And literally I'm just do, I'm just doing what this says, except changing the name, right?
New. And then all of the things that it has, which are listed nicely now for us in here. So in theory, we have all of them right there. Boom.
And then the beautiful thing is once this is there, we don't really need this anymore because we have it in code. You don't need it in writing if it's in code now.
So that's gone.
Code's better.
Um, and yeah, so let's do that. So title dot doo doo doo doo doo doo, right? So A simple way to do this would be to just delete this legal name and then do, you know, params, and then it's just the same, you know. Uh, it might be difficult for me to— there you go, something like that, right?
Where you basically say legal name, and you could, you could— there's a way to do this more efficiently, but for now let's go with this. Uh, and then of course verification reason.
Oh, I forgot something. This won't be exact, but we'll start there. And then we also need commas, which is what I forgot. I'll just have to do it manually.
Right.
Something like that. Uh, and then you can see this kind of does this. If verification.save succeeds, you know, if it's, it's, it's true, if it, if it kind of worked, then where it's gonna redirect to, and this is where this comes in.
The pseudocode, right, is this kind of little bit. Else, if it's false, if it didn't work, uh-oh, what do I do?
I render, in this case render new, but redirect to root path or something like that, right? Probably wanna do more. And what I like to do is I like to do an exclamation mark. So it sort of basically just means like it's a, if it fails, it's gonna show, it's gonna like error out instead of just do a soft redirect. So I kind of prefer this just to, you know, see all the errors that may exist instead of hiding them. Because sometimes Ruby can kind of like handle them, but you kind of don't want that. So anyway, Let's do this. So we now, we need, the funny thing is, you know, the pseudocode is redirect_to, the real code is redirect_to. So, uh, you know, not, not too crazy.
So, uh, yeah.
So anyway, now if, and this is, this kind of goes into here, if verification. And I, I, there's a way to make this better.
I'm sure someone knows, but we'll do this for now. Equals 0 or, or—
I know I can make this better, don't worry— or, or 1, which out of the 2 top reasons are about accreditation, send to this one, else send to that one, right?
Uh, something, something like this.
Now if anyone wants to comment Let me know if I made a mistake because there's a good chance I did.
Um, oh, let me close the Discord.
Um, Tony, just watch, you'll see, you'll see. Trust, trust the process, trust the process. Um, you'll see how many customers this thing has without doing any marketing content for Um, but unfortunately we'll get into that in chapter 5. So a little bit, uh, so that's that. And then it redirects and then we can worry about what happens later. But ideally this is the thing that saves, uh, all that data. Um, doesn't do supporting documents or whatever yet, right? But in theory, this should kind of work. Um, so I'm sure it won't, but there's only one way to find out.
So let's do it. Let's go back to, uh, whatever the URL is for this. 127 blah blah blah.
Huh?
I have zero.
I don't get it.
What?
All right.
Weird.
Um, cool.
So let's do this.
I probably wanna fill these things out actually with better, uh, better thing like identifiers, otherwise they don't fill in nicely.
Um, yeah, which is kind of annoying, but, uh, yeah, you know, things like name, street address and stuff will get, get things, uh, autofilled generally better. Actually, let's do, uh, HTML forms address.
Let's see.
Let's see if there are actually standards to this stuff. And I'll just copy.
Type street.
Oh, that's cool. All right, there you go. Type street. Type street. Type city.
Type—
Type zip county. I don't think we asked for that. Type country. Oh yeah, cuz that's gonna be, oh, maybe I should do that. That's, that actually be easier for me. Simplify my life a little bit. This might lead to some jankiness, but let's do it and see what happens. This keeps my life a little simpler if this works.
Country.
Oh, a name is what I would need, I think, too.
But that's pretty—
oh, ID equals Audible. Is that a thing? Or is that just from this? Yeah, probably from this.
Cool.
Yep. That definitely janks some stuff up, but at least that stuff's kind of loading now. Uh, full name autofill HTML. Let's do that one too. The field expects a fill name using name rather than breaking the name down. Cool. So that's good to know. Name, value name is—
wait, wait, what?
Can I just do type name? Is that probably what it's gonna want me to do?
I feel like that is in line with all the other ones.
Oh, that's weird. I don't know why it doesn't do it there. Um, but anyway, I ruined the design, so I'm gonna have to go in and fix that anyway. So let's do that. Um, one, it's no longer select, so I can kind of get rid of that.
I can also get rid of that image because I'm not gonna—
uh, yeah, let's get rid of it.
Don't need that image. You can always add it again.
We're also not going to need any selects, so we can get rid of this one.
And then here we're going to need all those ones that I added, right? So Type text.
Uh, what is it? Text name. Did I do— I don't know. Uh, street address, city, state, zip code. I'll just do apartment number. I don't know if that's a real one, but let's go with it.
All right.
Street address is street type street. Oh, and type text. Okay.
Nevermind.
Sorry. Uh, street. So I didn't do that one yet.
Go back.
Hang there. Okay. Zip code is type zip.
Zip, uh, and then finally country.
Yeah, it looks kind of nice. I mean, I kind of like it actually, but yeah, I kind of like it.
Is that kind of weird?
I don't know, I kind of like that design.
Use autocomplete name with type names.
Okay, thank you for the help.
Autocomplete.
Go back up here.
Yeah, um, I'll fix that.
Might as well, I guess, you know. Second row, third row. I don't really like adding these, but country. I think I don't need this. Top should be 0, and margin top should be 0. A country is no longer— why is it no longer doing it? Why is this no longer doing it? Is it being over—
oh, it's being overridden. Oh, by, uh, by this input type.
Okay. Yeah, it makes sense.
I guess if it's input type country, then I don't really need to, to use the class name at all.
Actually kind of— oh, that's kind of weird.
Top. Okay, whatever.
That's good enough. I have all the things, right?
Roughly.
Yeah. Cool. Awesome.
Great.
So back to what I was doing before.
Bye-bye Supabase. Sorry. Um, I'm not good enough at JavaScript.
Um, let's test it.
So, well, one, we need to make sure we're using a, a form properly in the front end.
So let's do that.
Um, generally I don't like form builders. I'm curious what, uh, other folks, uh, think about it. Um, I generally don't.
Um, But might as well do it because it's in the tutorial, isn't it? So let's just change this to form width, and then at the end this changes to, um, I think I'll leave these be for now, uh, Hopefully it'll actually, no, I probably should change 'em. It's gonna ask me to do all these things, huh?
What do y'all think, Miguel, Matt, should we switch to FormWith or should I just keep it like this?
I'll think of it.
I mean, I don't wanna rewrite all this, to be honest.
I think it's fine. Ah, fuck it. I'll do it. It's the right thing to do. This might lead to some jankiness. Uh, let's try with one thing and, and see how it goes, and then we can commit, commit to it. Um, and see how it goes, right? So Let's see what that looks like now. Yeah.
Yeah.
It's not a big deal.
Yeah. I might as well do it then. It might actually make it better.
Like a lot of these autocomplete things, hopefully we get, um, actually wanna make sure that this supports all those. Uh, things that I'm gonna want to support because there are a lot of those things. I'll change it. I'll change it.
I'll change it.
Um, I just need to make sure that there is a Things like, oh, wait, name field.
Yeah, see, there's no name. That's kind of annoying, right?
Like autocomplete, I guess autocomplete is probably supported somewhere.
Sorry everybody, I'm just, I'm just trying to learn.
Uh, what did I do wrong here?
Form with model seems right to me.
No, this should be form for— I think form with is right. Um, Yeah. Form with Omar.
Sorry.
I don't know what you're referring to.
Sorry.
Um, whatever. Let's just, let's just, uh, let's just move on. I'm just gonna keep it like this for now.
Um, don't worry about that later.
By the way, this code's open source.
So if anyone wants to chip in, let me know. After this weekend, cuz I kind of wanna show everyone just kind of me doing it, but, but maybe afterwards would be cool. I'm happy to, you know, if this makes money, then happy to talk about that as well.
Oh yeah, you're right.
This should be verification. Thank you.
I mean, this shouldn't really matter cuz it's gonna be nil anyway, but yeah, you're right. It should be this for if it fails, et cetera.
So cool.
Um, oh, actually, yeah, then I'm not going to want this to be a hard thing. It's better like this.
Okay, sorry, I've been stuck in this point.
So let me do verification, legal name, um, and then ID, legal name, right? Something like that. Article or Verification.
And then we can turn these into nice form fours or whatever, uh, when, if and when we want to.
Um, but yeah, let's go with that.
So the, all of these are gonna change, right? So basically all of these kind of names, uh, that I have are probably going to need to be updated to be verification.
Nope. Verification.
Like that.
And then they don't really all need IDs. I think IDs are kind of nice because then when you can like, you can like click on the label to do it.
Well, in theory, I don't know why that's not working. Maybe I'm good. Maybe I should revert this then. Label name. Label for— oh, it's verification label. Yeah, there you go.
Cool.
So it's kind of nice when you click, it kind of highlights it.
For example, you could do the same thing here. You could do verification street, right?
Something like that.
And then add— I believe you need this ID verification street. And now you can click that and it'll autofill, you know, kind of auto-select that. So anyway, I'm not sure if you actually want to do that, but, but, uh, some people don't like it, but I like it.
So, um, cool. So that looks good.
Email. Okay, let me get through everything else. So that is fine. That's good. We're gonna need On this set of things, we're going to need the same thing. Zip— no, this actually is zip code. The rest should match, I think. And then finally, we will do verification zip code, and this will be verification.
Oh, I already have this there, so actually we're good on that one. And then email address, email address, and supporting documents.
Again, we'll worry about that at the very end.
So this should still look the same. And hitting, hitting that did something. So cool. Yeah. So that's good.
We're, we're making some progress.
So that generates that. I do probably want to use strong params. So what I can do is, basically, I think the way strong— actually, no, let me do it without. Oh, it'll just do that.
Okay, cool. Good to know.
Do, do, do.
Well.
What I am a little confused about is how do you say, how do you say where, I guess it just defaults to post create.
Um, so I might need to just change this to create. Actually, it's probably the easiest semantic thing to do. So I'll change this to create. So now you have new in theory.
Um, but it, you know, in this case, just root path.
Um, Actually, what I would rather do is do render, uh, and do new. And then instead of having the welcome—
whole welcome thing, what I'd rather do is just delete. I don't need welcome really.
Um, instead what I can do, um, is go into and just move, move this into new and then change this into— change this to new and change— I don't mean like I'll change this to thanks, get rid of welcome completely.
I actually don't even need this page, right, because we're doing the Stripe thing. Um, But in theory, I can get rid of—
I believe I can just get rid of all this crap. Um, I don't need it.
I can just have the VerificationController. Like, why do I need more than that for this simple thing?
And then root is going to be VerificationNew.
So you have the root. You won't even have thanks anymore. I'll keep it there for now.
Um, did I add VerificationSubmit? I don't know.
Um, I think you need root, then you need thanks. You got the post, which is, uh, not gonna be this anymore. I don't think we'll, we'll probably be able to simplify the routes actually as well if we're using all this kind of standard stuff.
Um, but we'll keep that for now. Um, actually I'll just make this submit and then dashboard. Yeah. I mean, it's pretty simple, right? So submit. We'll do that.
I know that's not create, excuse me.
So let's go back and make this create. It's all create, might as well make it standardized. Um, and then I will be doing legal name and, um, yeah, so I think everything looks good. Let's see what the form's URL is.
See, it's just set to slash. How do I—
I need to set it to, uh, create, um, right? I guess, yeah. Why is it not doing that? Um, and the reason is Why is it not being posted? Good question, good question. Let's go to the top. Yeah. See, look, it knows, I guess.
Don't I need the routes?
Is there no routes needed for this? Um, yeah, maybe I just have to simplify it. Well, I'll get rid of thanks and then what I can do is Just do resources.
Actually, no, I'm gonna keep it like this just to do it. Um, but yeah, I'm gonna add, I'm gonna add it right there.
So let me do form with path. Come on, API doc.
Slope.
Oh, all right. URL. That's what I wanted.
Form with—
I actually don't use verification, so I don't even— I guess I'm not using any of this, so I can just get rid of this, right?
URL.
And what is the URL? It is create, right?
So boom, awesome.
I think that should do it. So let's refresh again.
Oh, label name, what the hell? Legal name.
There you go. Um, cool. So let's do that.
Good test, doesn't work completely. So Hmm, interesting. Um, I might have to work on this a little bit more to get it to do exactly what I want. I might just get rid of apartment number actually and just do it all with street address. Yeah, that feels better to me. Awesome.
One last thing. I'll, I'll keep it in the, in the DB for now, but we can get rid of it soon. So let's test it. We got that.
We're going to say I'm that.
I'm going to say that's my email. Oh my gosh, I'm redirected to Stripe to pay $50. No, wrong, too much, too much.
I don't want to pay that.
Um, but let's do— let's look, let's look at the last verification created. Legal name is nil.
Oh, it's all nil.
All right, so it did get created. And let's see how many there are.
Uh, count— there's one.
So that was created. But to someone's point, I'm pretty sure I'm calling these incorrectly based on this form input. I think I probably have to do params verification legal name is my guess.
Um, And easy way to figure that out.
Actually, I don't even need to do that.
I can just look at this and see what was sent up, right? Yeah, here you go.
See, verification. Yeah, exactly. So all of these params, I'm just gonna do verification and then of that, right? It makes sense. It's just like nested one level, right? And then the reason is because I haven't actually done the verification reason properly yet.
Um, Really, I probably should just do—
oh, I need value here, probably, right?
Um, so I'll probably do— is it—
what is it?
RadioButtonValue. Let's see, is it value? Cool. So value, I'm just gonna do 0, value 1, value 2, and then I can just clean—
oh no, this is Oh, this is an integer, isn't it? I think this should work.
I think it'll convert.
Um, but we'll test all this, um, which is kind of the point, right? So let's do it again.
Boom.
Upload. Boom. Then go back here.
Last.
Boom.
All right, Sahil Lavingia.
Email.
Boom. Apartment numbers?
No.
Fine, we don't need it.
Provo, Utah, blah blah blah.
Country is nil. All right, so that's bad.
Uh, why is that? Verification country, um, because I don't have name here. All right, that's probably fixed.
And verification reason is 0, which is a—
0 is the number, right? So if I do lot Verification reason. Yeah, it's a little less than ideal.
So what I'm going to—
what?
Shit, I didn't really— oh, it's a string. All right, fine. I'll just do this for now.
There's actually a better way to do it. Actually, I can— I'll do it now because it's fun. I really like this part, which is I can just do verification. Shoot, accredited investor. And the reason—
what I should do actually is the opposite, qualified purchaser, and then switch these over. Sorry, I saved something to my clipboard, so I don't want to get rid of it.
But that, and then I can make this a function on verification. If I go here, there's nothing here, but if I make that, a cred— a qualified purchaser question mark, then I can return this, right? I can basically say if equals, in this case equals 2, right? The, the last one, then it's a qualified purchaser, which is I send them to this other URL. These are test links, obviously. Um, but yeah, that, um, test mode.
So that's cool. Um, but that's fine.
Um, so let's do it again. Let's do qualified purchaser this time.
And oh no, it failed.
And the reason it failed is cuz I don't need verification here.
That doesn't exist here. It's just self. So it's just that. And I think I can send the form again and it's gonna send me $50. Awesome.
And I can do this. It's gonna be 2 and boom. Awesome. So I'm coding in Ruby. So yeah, boom. Awesome. Great, great, great, great stuff. You know what's awesome? I can freaking— oh, I already clicked the button.
Damn it.
Well, no, I can click this one. Save to DB.
Oh, that feels good.
We're getting closer every day.
Um, all right, should I do the dashboard or should I do uploading documents?
I'm running away from this. Um, let's do uploading.
Might as well.
We're gonna have to do it.
Yeah, let's do it. Oh, that also submits the form.
That's weird.
But it's not a, it's not a submit button, but whatever.
And I can add some, some jQuery to potentially, and you know, make it a little bit nicer. But yeah, it works.
I mean, it's starting to do its thing.
You probably only wanna show it in the dashboard actually if they've already paid. Oh yeah, no, that's what, that's another thing I'm gonna need is I'm gonna need like a, like a pay payment status, right? Because initially it's gonna be like sent them to Stripe to not having paid immediately. So I'm gonna have to add that probably. But that's pretty easy.
That's pretty, that'll be pretty simple.
I think uploading, uploading documents is the scariest part. So let's do that.
Uploading files to Heroku. Um, sure. What should I do, this one or this one? Let's do this, a little bit more recent.
Might cost a bit of money, but let's, let's see, $35 a month. Well, if it saves me an hour a month, it's worth it.
So let's try it out. We can always, uh, Do something else.
Hmm.
Why is this not showing up? Am I not logged in?
That's weird. That's weird.
Maybe I'll do it here then. Configure add-ons. Uh, what is it? Simple File Upload. Basic Submit Order Form. I don't know what an order form is, but sure. Enterprise Speak.
Um, so I have that set up.
Oh, I guess I could have done it there too.
Cool.
Um, let's do it. Yeah, uploading is pretty easy in Active Storage, is it?
Hmm.
Um, well, we'll see how far I get doing this. Cloudinary with Active Storage.
This might be too much for me, to be honest.
Um, uh, maybe not.
Okay, yeah, let's give it a shot.
Let's give it a shot.
New service.
I am not a robot. I'm going to make a task for myself to recycle passwords. All right, give me a sec. I'm going to have to verify my email.
All right. Let's say I wanna, I wanna take a break or be done, or I'll probably take a break. Maybe I'll be back. Validate my, but yeah, I think I, I think I should be able to finish all of the uploading stuff today, hopefully.
And then. Uh, maybe even the Stripe webhook stuff as well. Okay. So that I should be able to log.
I did. What the heck?
I did.
Don't read my email. Don't read my email.
Don't read my email.
All right, I guess I had to be logged in.
I tried doing it from my phone.
I'm a developer.
Ooh, upload my first asset. Exciting. Ruby.
Oh, they do resizing.
Oh, cool.
Interesting.
Thanks, uh, for the suggestion, Miguel. I think you're, uh, Let me know if you want a job.
You know your stuff.
Um, all right.
Start configuring Ruby. Great. I know Ruby. I can do that.
Awesome.
And then I'm gonna need this stuff set up.
Um, and I will put this in, I assume config. No, is there not a config? Oh, here it is. Uh, I guess it can go in initializers or I'll just put in here. This seems off. Don't—
wouldn't you want—
I feel like I'm doing something wrong, but, uh, whatever. All right, I think I I did that. Upload your first asset.
And yes, Charles, it will be available on YouTube forever, for better or worse.
Okay, this, and then, you know, part of this is going to be once you save it Or actually what I'll wanna do is on this, I guess we don't really need a public ID. Maybe it's gonna ask for one. It probably is, huh? Oh, whatever. Let's do this.
Implement your own can be called directly from within your custom coder.
One of the do to do. Awesome. Good to know.
OK, I probably do need a public ID.
So I think what might be good to do is basically take supporting documents, upload them all.
Each one should have a public ID.
Of public ID, which would be something like supporting document for, and then it might be like legal name.
And there might be multiple, right?
So it might be like loop through them, something like that, but something like that. So cool.
And there is an upload widget.
Uh, it's kind of ugly. Ideally we can just use the direct native uploading, which I think we can, cuz I think I saw something. Oh, here it is. All right. Config. All right, let's do it.
Great.
Maybe I should have put all this stuff here. Use Cloudinary tells development RB.
Yep, it'll be saved to my channel. Okay, that's really all I need. I mean, what about all, all this stuff I added over here?
What about all this stuff?
Pretty sure I'm gonna, I'm pretty sure I'm gonna move this.
I'm gonna actually delete this. I don't think I need this file. I think I can just put it here, right? That feels like it makes sense to me.
Um, but we'll see.
Um, include Active Storage. All right, I can do that in the JavaScript bundle.
So let's go to JavaScript. There's this bundle.
Huh.
Um, this looks different than anything I've ever seen. Um, but presumably you can just do that still with it. Um, it might— maybe it is too much for me, to be honest.
We'll see.
Various features of Active Storage. Oh, okay, cool. All right, let's do this. Active Storage. Time to set up Active Storage schema. Nope, gemfile, image processing. I don't need it, I think, but don't you want to do direct uploads? I, I would think no. Mm-hmm. What was the thing that you said? There is gonna be Like a URL that I can just grab from somewhere.
Somewhere.
Uh, I don't know. Where is it? Oh, there you go. API, uh, environment. Oh, I see. Cool. Gotcha.
I see.
Yeah, that makes sense to me. So basically that's all done in the URL.
So what I can do then is re-add that Cloudinary thing. But instead of having all this, just delete it. And I can create an initializer that can do— And I can just do something like this. I think that's—
oh, what?
That can't be real. I think this is, uh, this is very ugly, by the way. Um, you can set those up later, but it would work without them. There we go. Where's the— yeah, okay, I'm in the dashboard. Cool. Okay, so, um, I'm paying for this as well.
Let me try this first. Honestly, this feels more in my wheelhouse, so let me try this, and then if I can't figure this out, we'll go—
we'll do the other thing. Um, is that cool? Actually, I've already invested in this. I don't know, I don't know what to do.
This just looks really scary to me.
There's just so many things that I have never done before.
Is there a Cloudinary example? No. Yeah, let's just do simple file upload. Sorry.
Let's go back backwards.
I can't figure it out, then maybe I'll do this again, but I think—
I would prefer not to head this direction for now. Um, so let's go to HTML, which is new. Um, maybe it's gonna be You know, in the head. So I guess we can just do it in the application.html.
I still think there's room to make a better file uploading service.
It still feels like too difficult. Um, create a simple hidden thingy so we can do that just by Adding this, and I'm not doing avatar URL. Instead, I will do supporting documents.
Save the return URL to your database. Um, one annoying thing is you can only do, um, you can only do one at a time. Uh, which is less than ideal, but not the end of the world, I think.
Um, so let's go with it. We'll see it. We'll see how it goes.
Um, we can always say, you know, upload a zip file or something for the, for the MVP or something like that, right?
Um, So cool. So that, okay. So that's fine to me. That makes sense to me. Oh, you know what I actually wanna do? I'm gonna make, yeah, I'm gonna, I'm gonna make the name just to match these. It's gonna be verification block, right? Verification, any documents. There you go. Okay, cool.
Um, and this won't even need to be another table because I'll just have it stored.
Um, I work too, maybe it will be another— I don't know, whatever.
Um, okay, so basically what happens is it's going to upload these. In order to reference these, you need to save the value parameter to your database, which makes, you know, tons of sense, um, because of course you have to do that.
So Let's just start with a single thing.
And in that verifications controller, we're only gonna have one.
We're not gonna use this anymore.
It's already gonna be uploaded by the time that this is, uh, saved.
And so I should be able to— what is the schema for supporting documents right now?
Oh, it doesn't exist. Of course. Um, I can do— what can I do?
I can do verify—
I can do supporting document URL, and it can be a single URL for now. And what I could do in theory is I could just make it so that every time you upload it, just creates like a new thing. Um, but I think for now it's, it's fine to, uh, just have one. So I'm just gonna have supporting documents URL, and that means I'm gonna run a migration, um, to add that.
Uh, and I have migrations already, so I can just steal my own thing, which was You know, add column, etc. So migration, uh, add supporting documents URL to verifications. And then I believe that should spin this up, and then I can just Add a string and that's gonna be supporting documents URL. And then I'm just gonna write bin/rake or what, what is the term? Rails db:migrate now.
Yeah.
All right.
So now if I go to the schema, you'll have supporting documents URL and then I can write to it with the supporting documents. And I believe that should be everything.
So let's try that. Oh my gosh. Sure. That's ugly as heck, but I guess hopefully I can update that.
That's cool.
I'm surprised it was that easy. And boom, you have the value, which is supporting documents, and you have the value. So in theory— It should work if I hit proceed.
Oh, almost.
Uh, just get rid of this and upload.
I'm just gonna say zip, uh, to make it clear that you can only upload one file., and then this should be params, as I'm sure people notice on stream. That should be that, right? And so should still kind of, should fail. And I don't have, the reason is that it's, it's succeeding is I need to add, uh, validations, right? Because you shouldn't be able to submit like an empty form. Uh, so let's add, and I think, you know, add validation. And we can add a bunch of them, right? Like we need all of those that we had in the schema. Basically all of them have to be present, right?
So we can just take that list, you know, we can kind of just go through all of these. Delete them, delete them. We can say validates true. Get rid of— you don't really need to validate those, but I believe every— oh, and of course these are all dupes now.
Um, you know, basically super simple. Just make sure that all of these are present. Um, and I believe if I do that, um, It'll fail. Boom, undefined method name.
Hmm, that's— oh, sorry, legal name is what I wanted.
And it's failing. It's not failing well, but it is failing. And you know that because it returned the failure of save. Um, and so like, yeah, this is a good time to kind of have it add some errors, I think. Um, so let's do that.
Um, you can see that right there, .errors.
Um, how do you do flash message in Ruby Rails?
So what I can do, I believe, is flash.alert. Oh my gosh. Um, and then this can be, you know, the kind of, uh, verification.errors, you know, kind of thing, right?
So verification errors. And let me just do that first. And I think there's even more here.
Um, but like, let's start there.
Um, okay.
I'm surprised that that passed or kind of succeeded. Um, puts agent.errors.
I would love if it went—
if it actually just redirected to— because it's annoying when you refresh this, it's It's not gonna work.
Hmm.
Interesting.
Where was my thing I was looking at before? Had a good example. And I'm sure this is probably the— all right, cool. Yeah, I'll go here. Okay, cool.
This is where you have the errors.
All right. Makes sense. So we can get rid of this, I believe, and we can just have something like this, like, you know, at the top that just says verification. And then, you know, p and this to be, you know, class error. I believe if we do that— oh, this is going to be nil.
And the re—
I thought this should always be— why does it always work?
Oh, I guess because it's using the model. Oh yeah, this might be a reason to use the model.
Even if I don't use it very much, what if I just did model?
Will that work?
No. So I think what I can do instead is just do a try or something. Basically like this, I think. Oh, it is present.
No, it should be—
why is this able— why is this strange? Weird, weird, weird, weird. Uh, weird stuff. I don't know why that's not working.
Strange.
Um, I'll do something else, which is Rails flash message, and I'll just do something simpler. And then we can add this again, something like this. And let's give it a shot. Oh my gosh, it worked! Um.
I don't know why it worked that time, so whatever, this is okay.
Um, what I will do in this welcome is, um, basically just add a .error_message class and, you know, classic red.
Probably don't want to make it that red. Um, right, so we can make it less red.
We can do AA and see how that looks. Or even an 88, you know, something like that. And yeah, I think that looks pretty good. Uh, it's probably just not bright enough. It's a red to make sure that people see that it's, you know, red. Okay, cool.
That looks good to me. Uh, the other problem is if I type Sahil Lavingia, And I, let's say I leave this blank, all it's wiped, right? We don't want that either. So we wanna make sure that it's still there, which is why I guess this kind of verification thing starts to, to be important. And why form, form width, et cetera, is actually kind of useful.
So maybe it is worth doing that model.
Let's see how much I get for free just by doing this.
Uh, it might be worth it. Oh, nothing. Oh, and the reason is cuz I don't actually have, oh yeah, I'd have to update everything.
So yeah, whatever.
Um, let's just keep that and then, oh wait, yeah, this is, I should also not have it at create. I should just make it.
I probably should switch to the form. I feel like that would be good to do.
So let me just do it.
Model article.
Um, there's an example right in here. I'll just do it.
I have time.
I have time. That's that.
I felt good about the upload.
Wasn't that bad, so I might as well figure it out. Of course that's not going to work anymore, but that's okay. I'll figure it out.
Um, okay.
Uh, let's go. Okay, let's see that model form with— oh no, verification is what I want. Um, and then I want to update these to form.label legal name. So I want form.text_field legal name. Actually, I'm gonna keep this the same because I have a different, uh, thing, but I think I can do this at least, street address. And this is just a text field. Make sure I'm not exploding everything.
I will want placeholders, so—
and I can—
I think I can still do stuff like autofocus true.
You know, stuff like this.
Yeah, so that's fine. I'm still getting most of the autocompletes, so that's cool.
Um, wait, what?
Why did I type this in? Placeholder. This is gonna be city, state, zip code, and these are all gonna be placeholder.
City, state, placeholder.
Nope, losing my mind, slowly losing my mind. And then this should be pretty easy because it's just country.
Country.
I did wanna avoid this, but I feel like it's worth it.
Um, honestly. So yeah, decided I'd just get it done with.
Um, but this caused one issue, which is now it's doing the separation thing again.
Um, And the reason is this is no longer true. So I need to change this to something like that, just temporarily, you know.
Um, easy.
Nope, didn't work. Oh, you know, it's probably because it's not gonna have to do something like ID or something. It's gonna be annoying, but don't hate me for this.
Yeah, cool.
Um, and then the POST is failing. Why? Because no route matches it.
Um, but routes, posts.
Oh yeah, I need to do Go. I need to simplify the routes, which would be—
I can just get rid of this.
I might even be able to get rid of root, I think. Um, but at least for now I can do resources verifications only.
Do I need that as well? Only, and then it's gonna be new create dashboard as well. Dashboard, right? Verifications is, oh, and listen and other, other things, uh, I guess.
But, uh, actually no, that's, yeah, we'll start, we'll start here. I might do another controller for the dashboard actually.
Um, all right.
So no route matches POST. Um, new verification create. Okay, so the create verifications path is /verifications, but this is not taking it.
Where's my new, new page? Um, and why is this not auto-assuming Why is this not auto-assuming the proper URL? Do I need to have it? That seems wrong, but maybe it'll get us closer to the right answer.
So all right.
Oh, something weird happened here. That was weird. You see that?
That looks normal. Then I hit submit and then this all gets janky.
Why, why, why, why? The reason is all of a sudden this is now a class called FieldWithErrors.
Oh, it's also Oh yeah, I don't have—
I don't need grouped inputs anymore, so I can get rid of the group inputs. I can just have this because there's no— that doesn't exist anymore. So that I can kind of simplify, and I can just probably make this street address. Field.
And then you have a nice little mirroring of these two.
So let's do that. Street address field. Um, and this will be ID Street Field. All right, cool.
Looks good. This is hella ugly. Actually, wait, let me test out.
Sahil Lavingia. Let's see what happened.
Okay, cool. Yeah, we're making good progress now. It seems to be autofilling. Get rid of country.
Try one more time.
Boom.
Except for country. Awesome.
Oh, let's try this.
Oh no, that didn't work.
Um, because it's not—
we haven't updated this, um, to the radio buttons. I think verification is an instance of the verification model.
It's not when you first load it though. Right. Because there's, I, oh yeah. Maybe that's what you have to do.
Oh, good call.
Yeah.
Yeah. Yeah.
You gotta do that. Yeah. Good job.
Good job. This is exactly right. Um, I just didn't have this in here. And I think if I have this verification— verification.new— then I probably can get rid of these. This refresh thing is kind of annoying. I wonder if there's a way to fix that. I'm sure there is, but I haven't figured it out. What I could do is say, get— oh, I forgot the— Will that work? Redirect to root path. I do redirect. No, I probably have to do redirect, something like that. Redirect to, okay, to, and redirect. And I'm just gonna do /home. Cool. Awesome. So I can just do Sahil. I hit that.
It's wrong, but it is filled in. And then if I refresh, it'll just take me back here and it will delete it, but that's fine cuz I'm hard refreshing. Um, okay, let's do these radio buttons now.
Uh, form width or whatever. Did I have this here?
Radio? Nope.
Radio button. All right, I might have to change a bit of the logic depending on the zeros and ones and what, uh, what, uh, Ruby wants, what Rails prefers.
Um, but let's give it a shot. I'm gonna change these.
This is now gonna be a form.radio_button and it's gonna be for verification reason. And the answer in this case, I guess, is zero.
And checked is true. And I believe I will still have this. See if I've effed it up. All right, looks, looks good so far. Let's see how effed up this code got. Checked verification, okay. Cool.
It's, um, and let me update the label.
Might as well, uh, actually this person label, um, so let's do Instead of— well, actually, let me update these first. All I'm going to do is change this from— replace this, and that's going to become a 1, and replace this, and that's going to become a 2.
You're going to select between those 3 options. And then I'm going to update the labels in this way.
See if I can do them all at the same time.
So these are all going to become form.label.
Don't need these anymore. Um, this will be verification reason.
This will now be the, the reason. And then for some reason it says value. I guess that makes sense because you're gonna need the value for, um, for each radio button, it's gonna be different.
So we'll do that for now. Change this to 1, change this to 2.
Oh no, I don't want these to be checked actually by default.
Awesome. So let's try it. So the second one is picked. Boom! Awesome. Third one's picked.
Awesome.
Cool.
Making good progress, everybody. Making really good progress. Oh man, I was a little—
I was getting nervous.
I'm doing better now.
I'm doing better now.
Okay, so I did that.
I did that.
Oh, might as well use the, use the field, I guess, for this, huh? Actually, yeah, should I? Yeah, I probably should, huh? Form.hidden_field supporting documents. Class, right? Boom. And this will create that. And then Oh my gosh, what did I do wrong? Something here. Oh, it's— this should be supporting documents or supporting documents URL. Supporting documents URL, I think, right? Yeah.
All right.
All right. That seems to still work.
I click that, it uploads. I can't—
can I un— can I like upload something else instead? All right, cool.
And then this doesn't work, obviously.
So cool.
That's good to know.
Um, Moving on.
I don't want to use, um, I don't want to use their crappy UI though.
Wonder if I can update it a little bit. Let's see, let's see.
Email address disappeared when you submitted.
Oh no, did it? Did it?
Did it?
Oh, you're right, actually, because I probably forgot.
Good, good catch, good catch, because I probably didn't update this one yet.
So let me—
that's easy, just take this one. Boom. Text field. Should it be? Probably. I, I don't know if, uh, email address and then autocomplete email, and then this is going to be email address. It's not going to be autofocused, right? And that shouldn't fix it. But, uh, yeah, let's see if this is pretty darn ugly, so maybe there's a better way.
And there, there is actually one thing I normally like to do, um, which is like, don't allow people to submit, um, unless all the fields are required in the front end, but maybe that's a later stage thing.
How do I remove the preview?
Oh, preview false. But no, I want to get rid of the—
I kind of want to get rid of it completely if possible.
Oh, it's so ugly.
Oh, I can drop a custom icon. Okay, maybe this is— maybe I can make it look better. Maybe I'll—
it's so nice to not have to think about this that it might be worth— I mean, freaking hell, come on, you didn't even get it to work using your own.
Oh, it's SVG.
Might probably not work with SVG, huh? Well, the border color is definitely ugly, so I'm gonna make that, you know, better.
Oh, will it actually update the drop zone now? Like it just uses—
oh, it's not terrible.
Um, Yeah, I'll go with it.
MVP.
It's an MVP. We can always, we can always improve it, but, uh, yeah, let's do it. So, you know what I'll do instead is, I mean, I could probably like hijack this quite a bit and kind of do our own aesthetic. Maybe there's a way to do that. Um, you know, like if I just take this, I, I mean, the problem is it's, it's Yeah, let me see. Like what if I made it zero?
Could you still interact with it? Yeah.
So let me, let me, let me, let me spend 5 minutes.
It might be worth spending 5 minutes on this.
So you have this thing now, right? Um, and so ideally what you do is you have some CSS. I mean, not ideally, right?
But what you could do in, I think is you could basically look at this iframe that they've embedded., and then just, you know, have, have some fun with it.
Um, like change the opacity, do position absolute, the width 300 pixels, you know, kind of thing.
Uh, height 100 pixels, uh, maybe 80, you know, something like that.
So then you can click it and it'll still work, right? So that's like potentially something to do.
Um, and I don't mean potentially, I mean I will do it. So let's do it.
Uh, and it is called widget frame, which is less than ideal.
I wish I had a better name, but let's just go to the bottom and just say widget frame. And like, let's apply that styling that I just did.
And in this case, you know, I'd probably make it zero, right?
You don't actually need to see it, uh, because you have this Oh, it didn't work. Why not? Oh, it kind of worked to some degree. Um, you gotta override them.
We're fighting.
Yeah.
See, so it still works.
So yeah, who cares? I think that's fine. Um, good enough for me, to be honest. Um, now what I wanna do is get the JavaScript events., and react, you know, react to it so I can kind of make it feel like, uh, that button is actually the thing that was doing the thing, right? So the way to do that is to give the form element a custom ID.
Okay, I can do that. I know how to do that. This is that, right?
Class. So let's give it ID.
Simple file uploader.
I mean, why not call it the same thing that it's already called? Don't see why not. I guess maybe if you have multiple and same thing. And then write some JavaScript.
So we can just go script type JavaScript script. Oh no. Um, and then what was the thing? Oh no, sorry, this is simple file upload. Simple file upload. And this is, you know, file uploader. Uh, and then you can just do this. Oops. I'll make this alert so I can talk to— see if this works. Awesome, it worked.
Cool. So what I can do is I can say const—
File upload button equals document.getElementById, and then I can just kind of do an ID file— oh no, that's not what I want. Here, ID file upload button, file upload button.
Button and I can say, uh, I can add a class to it or I can change the text.
What should I do?
I could say, I mean, you could technically still upload it. Um, I can say, yeah, I'll change the text. I'll just change the text, right?
That should be easy enough.
There's a little bit of an issue, which is there's the, the, uh, icon. So what I might actually do instead is add a span right here and then do ID, you know, file upload button text.
And then I can just change this to text. I can make this the text and then I can update the text, uh, JavaScript. Update text of span, you know, something like that.
And what is the answer? Oh my gosh, it's so easy. Just, uh, it is recommended not to use.
Okay, so yeah, so let's do that. Equals So let's try that. Upload this thing. I wish there was a—
yeah, that seems to work for me. That solves the problem.
Change the text for the file name.
Good old Import to the rescue. Yeah, the only caveat would be after uploading something you won't see any changes. Yeah, it— I mean, it's definitely not ideal. But I think it's okay. I think for kind of an MVP, what would be nice is if they had other events that I could use. I'm honestly surprised, like this is actually a pretty awesome service. I feel like honestly there's a great business here. Just do this, but like add 10 features and you'll, I mean, I'll pay for it. I'll pay easily, you know, whatever this costs, $35 a month. Business idea for anyone who wants it. I should honestly start writing a list.
I'll write a list actually right now.
Who knows if this is a real problem?
I don't know if any other, anyone else has this problem, but probably you'd think, right?
Well, it seems like really that's like the only event. I mean, that's kind of bonkers. They probably built this like ages ago and haven't touched it since.
But that's whatever, it's fine, fine with me.
I mean, it's, uh, it does the thing, it does the job. So I'm gonna call it done on that one.
So boom, awesome.
Add to queue.
Um, well, this is kind of a weird—
yeah, okay, so this make— this kind of makes sense. Yeah, what I have to do is I have to do the Stripe stuff.
I'm gonna uncheck that.
Yeah, I'm gonna uncheck that because I'm gonna need to do that next. And that means adding some stuff to the schema again, right? Because the issue, one of the issues at least, is that we're not currently, yeah, having any, any, we have no context on like, has this person paid or not? Or whatever, and we plan— I think the reason I built it initially, like thought about it was, you know, it was one thing, right? With the Stripe credit card stuff. But if we're using checkout as kind of the MVP, which I think is fine. I mean, it's not ideally fine cuz they're kind of entering the same information.
Hmm.
Actually, yeah, that makes me think that maybe I shouldn't do it that way.
Let me see.
Let me see if there's a better Stripe.js option out there.
It would be kind of nice to just use— what is this? Is it dark mode? They have dark mode. Cool. Green, interesting choice. Yeah, I'm going to try.
I'm going to try. I'm actually going to try to do this because I think we have time.
So let's see if we can figure it out. All right, we got time.
I'll spend 20 minutes on it.
How about that? I'll spend until kind of 4. This other option.
Now we don't need image processing, awesome.
We don't need Redis, we don't need all sorts of this crap, but for now we'll keep it.
Honestly, it's kind of crazy how small the gem files are nowadays.
Um, but let's add Stripe. Uh, where should I add it? I guess I can just add it here. Stripe, uh, and then bundle. But that seems wrong.
Stripe already installed.
No, that seems off to me. I haven't added stuff in a while, huh? Um, whatever. That's weird. Do I not have—
I'm confused. Why is this—
why did it not require me to do gemfile.lock? Is there no Stripe?
Huh. Weird.
I don't know why it didn't show an installing thing.
Whatever.
Whatever, whatever.
All right.
So to have Stripe, to have elements available on your webpage, add the script to the head of your blah, blah, blah. Uh, everyone tells me to add it to the head, but is that really the right choice or is that the safe choice? All right.
Anyway.
Um, cool. Making progress. Go to new, just like we already have this nice little thing. We can just add to it with vars. Feel like they should update that, but oh, they probably did already here.
Yeah.
Might as well use the, the fancy newfangled stuff.
Rest is the same. Does it change everywhere when you do that?
Nice. Good, good on Stripe on that one. Cool.
Um, once you, um, you create, you can create an empty DOM within your payment form, whether, whenever you, wherever you want to add it to put a container with the label or an extra label with the form.
Okay. Yeah. It makes sense to me. Charge. Yeah.
You have a thing, you have kind of a credit card. Um, yeah.
Let me just like paste this whole thing in here. Um, right there.
Yeah, currently I— that's what Samantha was currently planning on using, Stripe Checkout. Um, but I, I think it's just not a great UX, honestly, cuz you have to like enter all this information on our side and you have to enter it again. Like I think it would be cool to kind of do it all in one, one place.
Um, so I'm gonna give that a shot.
When the form above is loaded, create an instance of a card element and mount it.
To the container.
I can do that, um, pretty easily, right?
I just have to do this.
And the card element simplifies the form and minimizes the number of blah, blah, blah, blah, blah.
Okay, sure.
I don't know what this looks like.
I wish they had an image of what this looks like.
Oh, it's older APIs.
Uh-oh. Oh, doesn't handle bank requests. What bank requests?
I think that's okay.
Cause I looked at this and I was like, oh man, this doesn't look as good.
Um, but maybe, maybe I was looking at the wrong thing. No, I don't want a pre-built checkout page.
I want—
what do I want? I don't—
they really are pushing this checkout page stuff.
It's pretty interesting and a little worrisome for Gumroad, to be honest.
Um, yes, this is what I want. Okay, cool. Yes, this is what I want. I want to embed this.
Perfect.
Awesome.
Thank you. Thank you.
Install the package and import in your code. Do I even have npm?
I don't. I must, I guess, because it's part of this now, right? Package.json. Awesome. Cool. Yeah. So I'll just add it here.
How's everyone's weekends going? By the way, I can't read Discord, it's too much going on, so just, uh, type in the YouTube chat. All right, we got Stripe.
Boom.
Awesome.
Making progress.
Um, next up, create—
oh wait, what?
Do I need Express?
Express?
I don't know.
I don't get what—
oh, this is like a server, server.js.
No, I don't want server.js. I want—
oh, whatever, I can deal with that later. I want this first checkout, which is the card element.
Yes, I can replace this with another form and sorry, that's what is this one? That's weird.
Okay. So that's that. Cool. And then the client, which is all this stuff that I already had.
Um, Actually, what I can do is 4242. All right, cool. Um, let's do with that.
There's a lot of code here. Do I copy this whole thing?
Will this all just copy? Okay, I mean, it's not wrong.
I guess I need all this stuff.
It's a lot, but I guess it's payments.
It's funny because Stripe used to be a lot easier back in the day to integrate.
It's become a little bit more daunting.
Uh, it actually used to be like 5 minutes, uh, back when I used it.
Oh, what? I'm gonna delete all this crap and start again. I don't know what's going on. This is weird. Okay, copy all that. Awesome. And then take it all, move it up.
Okay, cool.
Okay, I've copy-pasted the code, so that's some progress. And then there's some CSS, I guess, but ideally not too much. There will probably be card error, card element, payment request, etc.
stuff. So let me just take this and put it in that welcome.
I probably need to deal with this at some point, cleaning up the CSS. But if you look at the Gumroad V1 store, it's not that much better. Can only do so much in a weekend, you know?
Um, okay. This is a bug or not a bug, but that should remove the space here.
Um, all right, so I've done that. Add an endpoint on your end, on your server.
I'll do that later.
Build a checkout page on the client, which is I load Stripe.js.
Do I actually load Stripe.js?
Do—
did I do that? Um, application.
Yes.
Then I have the— there are— they have polyfills and they have this client.js, which they load in, I guess. I just put it in right at the bottom. Uh, which is fine, I think. And then, yeah, it's like not too bad.
I mean, it's, it's, you know, 100 lines of code, I guess.
So I do that.
I define the payment form, uh, which is what I did, I think, put in here, right? Payment form. Yep, payment form.
Awesome. Initialize with this publishable key. Immediately make an end—
make a request to the endpoint on your server as soon as the page loads.
Okay, so that is something I did not do, which is create payment intent. So I'm going to have to do that. Rails, create payment intent. Give me good APIs, please. Please give me some good examples.
Amount.
See, the problem is I want—
I might want this to change, right?
So how do you deal with—
can you reissue it? But yeah, probably it is.
Um, sure, so let's do that. Uh, we gotta create a new controller. Actually, let's just use the same controller. Don't tell anyone, uh, but I think it's fine. Um, I'm just gonna— what was it?
Create payment intent.
And then I'm just going to send people to verifications.
And that's just going to go to create payment attempt.
And then we're going to go to that controller.
And we're going to just create a new one. And I might be able to get rid of this, but I'll wait just in case. And then seems like what we do here is that this is probably not, um, where you'd want all this code to live. So let's change this a little bit. We just need to do that. Uh, this is gonna be $25. Um, Yeah. So sorry, what did I delete? Oh yeah, the require Stripe stuff.
Yeah.
I mean, maybe we need it up here, but we probably don't want the API key there. So what I think we can do is create a Stripe.rb. And whoa, what the hell? No, that's not what I want.
It's start.rb.
And cool, so we have that. Um, most of these things are optional, which is good to know.
This is a little worrisome to me because the price changes based on what you select, but I assume we'll be able to just ship and ask for another payment intent if that changes, and we can quite easily support that.
Oh no, cannot load such file, require Stripe.
Am I doing that wrong? Do I not need that at all?
Maybe I don't need that at all.
Oh, there's something here. Um, oh, whoa, there's all this stuff that's showing up now. Oh, that's probably because not nearly enough of what I copied from them That's good. Um, and the reason is they had a bunch of stuff in here. Payment succeeded. Yeah, so I think I can just get rid of a lot of this crap.
Um, Yeah. Do I need all this?
I don't think so.
I think I can actually, I'll keep, I'll keep it for now.
And when, when things are working, we can delete everything, uh, that we feel like we don't need. So I don't wanna accidentally make my life hell. Um, and what I will need to do is add another label called payment info, just like before. And it's ugly, but that's okay. Pay now. Hmm, okay, what is going on? What's any errors? Anything I have to worry about?
Oh yeah, create payment intents, obviously not gonna work, doesn't exist yet.
Um, why is it doing a POST?
I mean, why is it doing a GET?
Why is it saying a GET? Oh, I guess technically it's not. Okay, fair enough. Um, fair enough, fair enough, fair enough. These are all failing because of Oh, cat's here.
Oh no, it is a post. Okay, cool.
No, that's good. That's pretty easy to fix, which is I believe I just put a post here. Okay, what is this? What did I do?
Hello, say hello.
You can stay here, just let me focus, okay? Um, okay, that is still 400ing, but I don't know why now. Oh, what does it say now? Enabling— what is this sortable.js? Okay, something's up. Okay, what does it say?
Routing no mat create payment intent.
Did I spell it wrong? Oh, of course. All right, give me another error, give me another error, give me another error, please, please give me another error.
422, unprocessable entity.
Awesome. Yes, new error. I'll take it, I'll take it.
Why though?
Give me, give me an answer. Why is this doing that? It is doing that because I love these errors.
Oh, so much better.
Backend errors are so much easier.
Invalid authenticity token. What? And the reason for that is probably that it's taking—
is the form outside of that form? No, it's in the form. Maybe I need to pass Hmm, okay, so purchase, okay, I'll ignore whatever this is for now. Maybe I can— yeah, okay. Show the customer the error from Stripe if their card fails to charge, and then load.
Okay, so nothing too crazy in the code.
I mean, it's pretty simple. Hmm, what's going on?
What's going on?
Why is this getting an invalid? Oh, of course.
Because it's trying to create a payment request without a CSRF token.
Okay, that's probably— I'm sure people have dealt with this for set credentials. All right, I— maybe they should add that by default. Where do I do that? Fetch, right here.
Okay, that fixes it. I'm—
I'll be happy, you know. Oh no, so is it that— is it still there? Yep, still there. 422, unprocessable entity, still happening.
And the reason is it's not—
yeah, so I mean Um, yeah, maybe I'll just skip it, skip it.
And I'll only do it on create payment intent.
I think that's fine. Oh, it's a 500 now. Another error. New error. New error.
500 error, which is uninitialized constant Stripe.
Uninitialized constant Stripe.
Do I do, do I do need that require? No, you, Bradley, you shouldn't need to pass along the CSRF.
I think if you, if you do it that way, you shouldn't need to. But oh, what's this Stripe Rails? Whoa, this is a lot of crazy stuff. This is probably too much, more than what I need.
But cool, I guess.
Maybe good to use, uh, to switch to. Um, sorry, I got distracted.
Um, all I want to do is require Stripe, uh, in the controller. Like, what does that actually look like?
I forget.
I just genuinely forget how to require.
Uh, require stuff.
Don't I have to require something somewhere? Is that the issue? Why does this person not do that require? Weird. Why, why don't others have to? I don't, I don't get it. I don't get it. I don't get it. I don't get it. Maybe I'm doing something wrong with calling, uh Stripe here. Payment. Let's go back to payment intent.
Require Stripe.
Where Do I put this require straight? I'm pretty sure I missed something.
Okay, let's do this. Gemfile has Stripe in it.
Awesome.
Config initializer Stripe.
Also exists.
Um, maybe I need more stuff, but I have the API key at least. Um, I don't think I should need anything more. But yeah, I mean, I guess, yeah, I guess I have the publishable key that I could put in the config, but whatever.
Um, oh, try rebooting server.
Oh, thank you, thank you. That is a good idea.
Turn it off and on again, you know.
Oh, why is this happening? What?
Okay, pray, pray, come on, fix, fix. All right, what happens if I scroll? Is there going to be a credit card form? Is there going to be a credit card form?
Is there going to be a credit card form? No. Oh no, why not?
And there's something—
I mean, there's less, um, there's less, uh, create payment intent processing. No template.
Oh, what?
No template found for create payment intent.
What?
I'm pretty sure that there is a Create payment intent right here.
Am I—
did I spell it verifications controller? Create payment intent, no temp.
Oh yeah, there is no template.
Yeah, of course. Um, yeah, sorry, that's stupid of me.
Um, let's go back, let's keep going.
I need to go back up here actually, set up the server, which is—
I had Stripe and now I'm creating the payment intent. Oh, and I have to return something.
Return the payment intent's client secret in the response to finish the payment on the client. Okay, so what that means, I have to return, uh, render— is it JSON or something like that?
Uh, render JSON Rails controller.
Come on, just tell me the answer. That's all I want. Okay, cool. This is what I want.
Render JSON, and the JSON I'm rendering is client_secret equals payment.
HumanIntent.client_secret.
According to that, I wish they had this code in Rails Ruby.
Uh, but whatever. I think I'm, I'm gonna send this video to Stripe. The team at Stripe.
Maybe they'll get some insights on how to make their onboarding better, though it is pretty good.
Oh my gosh, it's here! We did it! It's alive! It's a live cat!
It's happening. All right, what happens if I just type in— oh yeah, it's not going to work, but Good progress.
Good progress.
Um, where did my payment button go? My, uh, oh yeah, I can change this back now.
Feels good.
All right, cool.
We can, uh, oh no, I deleted the, I deleted the, uh, credit card from here. Um, oops. Oh well. Figma slowly gets out of date, you know, as you make progress on the actual product, you're like, ah, whatever. No need to keep it perfect, though it would be nice.
So boom, back. Submit information for verification.
Close this. We don't need this.
Good with that. Good with the file uploads.
Good with that for now. Labels, forms. All right, cool.
Um, not done yet though. Still got more to go. The payment— I haven't issued—
I haven't made a payment.
Um, yet, but feels like the hard—
most of the hard seems to be done, you know, set—
setup is like, you know, 90% of it, you know?
Uh, yeah.
So, okay. This is a bit ugly, so I don't need— what I think I want to happen is when you hit You know, you render all this stuff out. Makes sense to me.
You get this, you inject it, you disable all the buttons. Oh, I see what you're doing.
You're disabling all the buttons. Oh, because you, yeah. Okay. Fair enough.
Complete payment when the form, when the submit button is clicked. So I'm actually gonna change this to form. I'm gonna use the main form. Like that's, I don't think, I think the only reason to care about this payment form is to submit the form, right? Cuz we're not using this anywhere else. So I believe I can get rid of the form and just kind of assume that myForm is that form, which also means I can kind of get rid of, you know, a lot of this crap and I'll just make this a submit. And I don't need—
I'll— I'm a little paranoid about button text, but I don't, I don't really think— I mean, spinning is nice and stuff. I mean, I don't think we really need it though.
If that, couldn't I just do this now?
Right.
Um, cool.
So that's less code for less stuff.
Let's refresh, see how it looks.
Oh, I probably need a little favicon too, which, you know, will just probably be this little dude.
Um, I don't need this pay now button. Pay now is the button text.
Which is the submit, which I also don't need anymore. Um, so let's get rid of that. And then card error. Fine. Like I'll keep that, I guess that's fine with me.
Um, and then I don't really need this. I mean, I get the point of it, but just for, you know, so basically you get rid of it all.
Um, what I'll do, yeah, I'll just remove it. I think it's fine, whatever.
Well, we'll have some errors, you know, in the code base, I think.
Um, but I think that's fine. Card error. Is there any other errors? Error message..
So I think what I can do is I can just update this.
Hmm.
I see the point. Like this, it's kind of nice to be able to, you know, have a, a, a button. But I think what I can use, I can just use this main button, you know, if it's, as long as the message is short enough. So what I'll do is I'll just change this to submit. And then I don't need it. And then when the payment is complete, I guess it's a bundle.
This is kind of confusing to me.
Oh, I want it to be an atomic event, right?
You shouldn't be able to pay if you didn't enter all the information. So it's like a little, a little worrisome to me to have it like this, but I'm sure it's fine.
By the way, should I make this full width?
It feels like it should be, you know.
Okay, let's, uh, Well, I mean, it seems like it's working. It generates the payment intent.
Um, and then you hit submit, you know, I think that's fine. Disable the button. Um, I still don't get this part. Yeah, it might be working.
So if it is working, then I think I'll just make it a little prettier because I think that's throwing me off. Like, it feels— maybe it feels buggier than it actually is.
Um, card element is adding all this crap to it. Card element, why, why do you have that look and feel to it? It's kind of ugly. Um, I don't think I need this.
Um, okay, I can see why you want the padding there.
Box-sizing border-box though, so we can make sure that your height is—
and I want the height to be roughly the same as these Inputs, which is 50px. Um, and I'm gonna add margin-top as I have on the other things, and I'm gonna make the border same, which I believe is 95. 95, 95, and then the background's white, which is—
it is, right?
So, oh, and the box shadow.
Don't forget the box shadow.
Um, let me see, you know, let's make sure that I take all the other stuff too.
Might as well, doesn't hurt.
Payment request button, I'll keep just in case.
Um, that's a dupe. That's needed.
That's a dupe.
That's a dupe. Let's do 15 padding to make it the same.
17.
And then color should be fine too.
Awesome. That looks pretty nice, I would say. Um, what happens when we go through it? I'm pretty sure I didn't finish, but let's do it and see what happens. Oh no, it didn't work. Why didn't it work?
Fill out the form. And the reason is—
do, do, do— it all seems to have finished. Supporting document URLs blank, but I don't believe that that is one of the requirements. Oh, it is.
Yeah, so maybe that's why. Um, okay, well, not a big deal. It's all entered. I'll upload a thingy.
It would be nice to have a little—
I guess I could, I probably could. All right, that didn't work. Why not? Has all the things including the image that I uploaded and email, but it did not work. And the reason is I have no idea. So let's go back to this.
So I created the payment intent, right? And I got that response back, and I know that I did, because if I refresh this page, it does do that and it returns.
I mean, I don't print out what it returns, but I guess I could see it in the network. Client secret, blah, blah, blah.
So yeah, I think it works.
Um, that part works.
Um, and then I have to build a checkout. So I load that, I define it, I initialize it. I fetch it. I initialize the elements. Um, did that.
That was kind of cool. It was nice inline stuff.
I did that.
Great.
Uh, created the card element. Um, uh, I did not do that, but that's fine. Um, complete the payment on the client. Okay, pay with card.
Uh, did I do that? So complete. So payment does loading.
Confirm.
Yeah, so I think what I need to do, I think I'm probably What I probably need to do— it's a little confusing. What I probably need to do is I need to save the information and then in the front end process the payment.
Seems, seems confusing to me. Uh, whatever. Okay, let me keep going. Pay with—
complete the payment call.
Confirm card payment, passing along. Um, and sure, I'll save an email receipt. Um, I already have an email, so I think that's fine.
Um, okay, what's going on?
I'm a little I mean, I get—
maybe it should be a separate— yeah, you submit the information, it saves, and then you pay. Ideally, it's all in one fell swoop, though.
Because you do—
what you don't want is you don't want people to pay for Stripe without entering the proper—
like, uh, whatever, let's just get it to work.
You know, it's 4/20, happy 4/20 everybody.
Um, but I don't really know what's failing. I don't really know what I'm gaining by doing this. But all right, let's do it.
All right, um.
Hmm, what's going on? Why isn't this working?
Well, order complete. What my guess is what's happening is that the form is being submitted, um, and okay, come on. My guess is the form is being submitted in the front end, so it doesn't actually have time. So yeah, I do agree with you, Miguel. Like, ideally the, the paint— the sort of payment actually happens in the back end, but Stripe has made these changes, and I believe it's because like there's just a lot of complexity nowadays and like what they want, what different banks and governments and stuff want people to want them to collect and stuff. So unfortunately, I think the way it is, is you submit a payment request and then you get kind of this like little token and then you can use it to charge the card. But the problem is, yeah, it does have this annoying issue, which is you have to kind of assume it becomes like not an atomic step. But I think it's fine. I think what you do is you just charge the card And then you hope the data is valid. And if it's not, you just send an email saying something.
I think it should be fine.
Yeah, so yeah, I think what's happening— I do think what's happening is that the payment form is being submitted.
So yeah, I'm confused a little bit by this.
Um, I mean, one thing I could do is I could submit and then the next— there's like a separate page that's just payments, you know, like, you know, complete. But I guess that's basically Stripe checkout. Um, When you go to submit the form, you will catch the form submission and send over the payment intent token. Do you have a URL that I can read about this? Problem with Stripe is they have so many different ways to, you know, integrate. Their stuff that it's like not obvious like what's the right approach, um, in my opinion.
Um, confirm card payment, pay with card, if that.
Otherwise it just does it, right? Like it just does The payment. Um, so I guess what you might want to do is at this point, don't pay with card.
You hit submit, right?
Is that basically what—
oh wait, fuck, this is to be form. Uh, get by ID. Yeah, this should be form. Maybe that's what I did wrong.
Form.
Can I give this an ID? Yeah, cool. Make sure that there's nothing in the console.
What is sortable?
What— like, where is this coming from? Dragula shortable. What is this?
It's just like a local thing that it's from something I have installed, I guess.
Yeah, whatever.
Okay, let's see if that helps. Maybe that— maybe I just not done that properly.
Oh.
Oh yes, sweet. Okay, progress.
Um, progress, progress, progress.
Um, cannot read properties of null.
Reading set attribute—
what?
Reading set attribute at order complete. Okay, so that's good, that's progress. I like progress like that. Uh, what was it? Order complete. Awesome. So the reason this is fail— this is wrong. So let's do this console.log result, and I guess I might as well do this just in case.
Payment intent is not defined. Um, it's right here to me. See, it succeeded. Seems like the payment succeeded.
I don't know what this is.
Pay with card payment.
Payment intent is not defined. Um, it seems defined to me. Um, Well, I'm making good progress, I think.
Um, I mean, this is exciting that it seems like something did happen. Um, but then failed, but it failed in a place that doesn't sound obvious.
Like, what? Oh, duh.
Oh, okay, sorry about that, everybody who watched that and thought I was being dumb. All right. So boom, I got that succeeded.
And then I get cannot read properties of null reading at set attribute.
Okay, well, we can figure this out.
This is actually my fault. I bet you, because it's this. Yeah, it's totally my fault. Uh, it's the stuff I deleted. Great.
So I can remove this.
Actually, no, I'll keep this payment intent ID.
Oh, it's already there.
Um, because I need the payment intent ID to actually— oh, I actually haven't paid yet. I think, right? Is that right?
Is that what you were saying, Bradley?
Basically you, you get the payment, the, you get the token and then I pass it to the backend, right?
I hope so.
I think so. Okay. So, well, loading is false, so that's fine.
Move that result message.
Okay.
Order complete.
All it does is, okay, so then this is on me at this point, right? So on me is I have the payment intent ID and it hijacked, already hijacked this form. It does the payment. Of the card comes back with the payment intent. Boom. And now I do what I wanted to do initially, which is submit the form. Uh, so, you know, something like, but the problem is now I, I feel like, how do you, how do you bypass this? Is it gonna trigger this again?
Um, anyway.
Um, so none of this is being added to the database, right? Because none of this is actually hitting like the actual backend yet because yeah, exactly.
Oh, kind of. When did, when did this?
12:21.
No, this is 10 minutes ago. I could be wrong, but yeah, I don't, I don't think any of this is currently hitting the backend.
I could also, yeah.
Anyway.
Um, cool.
So let's try it.
So you have the form. Um, and okay. It, it, oh no, this is the payment actually already succeeded. Um, okay.
So that's, mm. Not ideal. I kind of would want to submit the form first, and then I'm confusing myself.
I just need this to work and then I can make it better.
Okay.
Um, so You disabled the button, blah, blah, blah.
You now, you need to submit the form with all the data, including the payment intent ID. And actually there should be instructions here.
I feel like on how to do it.
I guess the problem is that I've now created like, there's like only one form. I think in their world they had two, like they had the payment form, which is like a separate form almost.
Right.
Um, now I've combined them, so that might actually be a little confusing, but I mean, whatever.
I think it's okay.
Um, how do I submit the form now that I, I want to unhijack it basically.
Do I just remove the event listener, but then I have to Would I have to add it again? Yeah, maybe that's what I do is I just remove the event listener and just like restore the default.
All I wanna do is like, let you know, remove.
Yeah. Let me see if I can do that. See if I can, if there's an example of somebody who's done something like this before. Yes. This is what I want.
How to restore default event listener to form submit. Oh, the other thing I wanna make sure that I actually, no, I'll wait for Stripe to tell me what, what they expect. What do I want to do with that payment intent ID? Do I just store it?
Store it on the, yeah, that's probably what I should do actually is store it on the, on the, uh, verification, each verification, right?
So that makes sense.
Um, Okay, let me remove this. Okay, I think the issue is in your removeEventListener call.
The second argument needs to be the original listener you wanna remove.
Oh my gosh, really?
I have to— okay, fine. AddEventListener. So I'm just going to do this, uh, StripeListener, right?
And that's going to listen. And then I'm going to create this constant, you know, somewhere over here.
Um, do this kind of thing. Ah, there's a Stripe—
Stripe example. Uh, cool. Well, that's funny.
Uh, well, I just need that, right, to basically prevent Pay with card.
That's pretty simple.
I mean, it's not nothing, nothing too crazy.
Um, submit the form, etc.
Um, and what—
oh no, this needs to be Stripe listener.
Okay, Stripe listener. And then I can basically do Um, form.removeEventListener, uh, and this is going to be onSubmit, and it'll be the Stripe listener.
And then I believe I can just do submit like this.
Right.
This would be beautiful if it worked. Um, I'm not insanely hopeful, but let's give it a shot. What else do we got?
I can make the favicon, I guess. Important stuff.
Um, Okay, let's give it a shot. Pray, pray with— pray, pray together.
Oh, card is not defined.
At— oh yeah, yeah, moving it out of there is a pain in the ass. Uh, card is not defined in the Stripe listener anymore.
Can I pass something to a listener?
Um.
Maybe I can just move this. Is there a reason that pay with card is here and then not in this?
The problem is this is not going to work because it has all this I don't think this is gonna work. OK, I have another idea, which is to just make it much— a little bit more complex of a function. So move this away. So it's like this again, and then we can figure out what we wanna do here.
But I believe I wanted basically do a, a standards form submit, um, which won't work. I understand because of this function, which does this., event.preventDefault. So it's just gonna— but what I think might work is we can set sort of a global variable or something, um, and, and just, you know, in that function we can, we can adapt, right? So for example, we do window—
just, this is just, you know, for now, window.paymentCompleted equals true. Right. And then over here you can say, if, you know, payment completed, then do these things, right?
And I believe that this should just work now because effectively what you're doing is you're saying—
oh, maybe not.
I don't know if this is a kind of what runs every time. But in theory, I might have to do like, you know, form, form.submit again.
But let's, I think that this might work. I think.
Form.submit is not a function.
What do you mean form.submit is not a function? Wasn't that what we had over earlier?
Okay. Um, that's a form. That's this form.
And you can do submit like this.
Submit is not a function.
Really?
Isn't it a function?
Why is it not a function? Is it because the thing got hijacked?
It's no longer— no longer gonna work.
Hello?
Form.submit.
Um, oh yeah, maybe it's because I have, uh, some problem with the name of the— I mean, not really. I don't see submit being the issue. Maybe, uh, maybe. So let's just change it. I mean, if people are saying that might be a problem, it's not worth— not worth it. Um, I'll just change this to submit button. It's not a big deal. All right, again, let's go.
All right, it failed, but I feel good about it. Um, let's see what the console says.
It's submitted. It submitted it. Um, yeah, I mean, I think it worked.
I think it worked.
Um, not a good sign if you think it worked, I guess.
Um, but what I can do now is get, um, get the actual, get the actual sort of, um, You know, the field in there, right?
So effectively what I can do is I can, I can take this, I can have like a payment ID, um, and I can just store it there. So I'll go back and down here.
And go into this part that's finished. And before I fully submit, um, what I want to do is I want to take this payment ID and I want to store it there, right? So I want to do document.getElementById that, and then I want to do, I think it's textContent or like How do you, how do you set the value?
They did it with this upload as well, right? No, I did it here, I guess. Um, let's say vanilla JavaScript update hidden field value. Simple enough.
.value.
Okay. Cool. That's pretty simple, easy.
.value equals paymentIntentId.
Oh, shoot. Right?
And if that's true, then I will have the payment intent ID here. And that's cool because then I can take— then I can go into the backend, which is in the verifications controller. So let me close everything that isn't that verifications controller and Now I have the payment intent ID, which is coming through this way. Um, right. Uh, and so what I can do is payment intent ID, and then I can save that. Um, and I can make sure that that's required as part of this, right? I can basically say I need this payment intent ID, and then what I can do is I can run a migration and I can do that add.
Sort of add, and then I'll do payment and ID to verifications. I can go in here.
Um, I can find the other migration I did.
I can add this, uh, payment intent ID. I can run it and we can do it again.
So we're going to refresh, close it all like we're starting from scratch. I'm going to upload my supporting documents.
Email, and then this. I'm gonna submit.
I should— I'm gonna make a note. I'm gonna actually—
let me submit. I'm gonna make— oh, it failed.
Um, but I'm gonna do this. I actually basically, because we're doing the payment the way we're doing it, like This should be really easy, so I don't really need to do this.
I can kind of move, just move it there. I didn't get the email with download link, which actually I'll do probably at the end.
But I do wanna make some small things.
Like I wanna do submitting, you know, when, when you're when you're typing.
So, uh, all right, well, that didn't work. Um, and the reason is, we'll find out in a second.
So let's find out, why didn't it work? I submitted all this crap, including an ideally a payment intent ID.
Awesome. And so I feel like I have all the things, but it didn't complete. And that's my fault because, you know, I don't say anything here. Uh, so it's kind of tough.
Um, what if I do this and I do it one more time? Aware that I'm getting close to 5, which is when I will—
apt number can't be blank, supporting documents URL can't be blank. Awesome, I love it. That's fine because we don't have apartment number anymore.
We got rid of that crap.
I don't know why That's been there for, for a while, but we don't need it. That's gone.
So that's good.
Supporting document URL is less good because to my knowledge, it's right here. I mean, if I take this, it's clearly not blank.
It's clearly not blank.
Um, however, It is obviously returning this failure. Supporting documents URL can, cannot be blank. Supporting.
So why is that?
And the reason is this should be supporting documents URL. I must have changed it at some point.
So good.
One more time. Oh no. Why is it going to Stripe checkout again?
Oh, it worked!
That's not what I actually want— wanted.
Actually, I need the thank you page now.
No, is this still here? Okay, it's still here.
It's still here.
Um, is the other thing here?
Is it here still? Shoot. Yeah, it's not here, is it? Um, It's okay, it's okay. Verify.
Thanks.
Um, and then let me just do a thanks right, right here, right? Def thanks. And what I would rather do is do thanks.
And then do ID equals and then do what the ID is, so verification.id.
In this case now, you can just simplify it into a single thing now if it's doing the thing. Change that back.
Then ID, the reason I want this ID is because I believe in this things.
You know, I have this, so I'm going to do that there.
And then here I'm going to do ID equals Bram's ID.
Um, you know, this would send me to like over there. Um, let's do it again.
So let's figure that out.
Uploaded 14/14/2022, et cetera. Submitting—
I will do submitting.
Boom!
It redirected number 8. And let me just go into Stripe verification letters and go into test mode.
No thanks. Oh, what? No, I just want to go into the dashboard. Oh, here. Sorry, missed that by a bit. Don't look at how much money Gumroad is processing today. Oh cool, saved.
Okay.
Um, well, oh, this is the demo.
So yeah, it succeeded. I mean, that worked. That was like that payment, right? Um, you know, obviously test data, but boom, $25, you know, fee from Stripe. Let's just make sure that this, you know, is kind of accurate. So verification.last.paymentIntentId 80.
Oh nope, nope, nope, nope, it's wrong, it's wrong. Why is that? Verification.last is, um, is number 8.
Where is the payment ID? Why is it not even listed here?
I guess maybe I have to leave and come back because I made those changes, right? Certainly doesn't help. All right, so I have this one, which is not that. So let's look this one up. Okay, I mean, sure, this is, this is here.
Oh, it's a different— oh, that's the ID of the payment method.
I see, I see, I see.
So the ID of the—
oh yeah, right here, there you go. So that is the payment, right? Oh, 0, 0. Let me just go back. 0, 0. Hmm. Hmm.
All right.
So I mean, in theory, if I'm not wrong, setAttribute.
Oh no.
How old is that?
Okay.
I, I've probably fixed whatever.
Oh yeah. You're telling me how to do the, yeah.
Cool.
Well, everybody just wanna, just wanna enjoy this moment for myself. Uh, can I zoom in?
How do you zoom in on— oh crap. Anyways, I'm gonna do it. I'm gonna hit the button.
Stripe.
Done. I do have to activate the account. Submitting. You wanna, you wanna, you wanna finish this up? Um, we got 4 minutes, um, until 5, which feels like a good— I feel like we're making good progress. Um, I feel good.
I feel good.
It's still tough. It's not gonna be easy. Tomorrow's not gonna be a walk in the park., to do the rest of this thing, but we're getting there. Um, so let's, um, try to do that last thing, which is getting that submission, the submitting thing, right?
Which is right here.
Uh, and this should be pretty darn easy, which is when you, you know, you hijack that submission, you know, does that payment, payment with card, blah, blah, blah, blah, blah, and just like I do this thing here where I change the button. Where did I—
didn't I do the button error, error, show error?
Uh, so, oh yeah, submit button.
Yeah, exactly.
So instead, what I can—
or I can still do that, but I want here, what I will do is Get that and change the text content to submitting or processing payment, something like that.
Right. And then what ideally, what, what this kind of does is, oh, you know what I'll do actually? I'll, I'll run one more test. Actually, this is not going to work because I didn't do the $50. I still have to figure out the $50 thing. So that's, that's actually one more thing I'm gonna have to do. Uh, $50 for qualified purchaser.
I actually have an idea to fix this in a second. Um, it's a little cheating, but, uh, you'll— I think it'll be fun.
But, um, yeah, let's do it.
Let's, uh, I mean, it doesn't really matter too much, but let's just I, I can make this form better.
Like, there's a bunch of polish I could do probably tomorrow. Um, like, for example, like, you know, it shouldn't have to— you know, for example, if you, if you don't enter the name, it can just highlight it in red, right? Like, it doesn't actually need to do the form submit. So there's more like that stuff that I want to do, but I'll do it at the end. Processing payment.
You're all set.
Woo!
We did it! Look, to a customer, we're done. I mean, really, like, we're done because in theory the rest of this could be manual. Obviously, you know, we're gonna do some work tomorrow, but, uh, I don't know if my mom's watching this, but my mom probably can't, um, you know, can't do this. So tomorrow, just to kind of show everyone what we're gonna do tomorrow—
oh man, I feel, feel good.
Okay, you know what I might do is I might, my joke, I'll just get rid of the $50 tier. I'll just make it $25. Less stuff that I have to figure out. So let's do that really quick. These are the best, best features, you know, just deleting stuff. Elon says, you know, the best product is no product. Can't break, no bugs. So I'm just gonna say this, uh, so that's done and I did that submitting thing. And so I think, I think I'm gonna be aggressive. I'm gonna hit this button. I'm gonna hit this button. And tomorrow we'll go through the dashboard and we'll do all the, all the other stuff and we'll see if we can get to this. That's unlikely, to be honest. But, um, yeah, let me just show everybody just to kind of go through the prototype again.
Uh, you have this thing.
I need to update this as we've made some changes. You type in the stuff, duh, duh, duh, you upload some documents. This is a little different now, right? We're not doing any of this. Um, again, like, you know, work within the constraints. This is what I love about weekend projects is it forces you to like be okay with honestly not good software, you know, software that we all know we can make better. Um, submit, you get this. So we've done all that, that part we've done. Uh, and this is what we're doing tomorrow, which is the dashboard. Board, which is, you know, I'll have to build auth. You know, that would be pretty simple. You just have to be logged into hi@verificationletters.com or something, and then we'll just do Google Auth. And then you'll see a dashboard of all the verification requests. So I'm going to have to add a status, right? Because there's these, you know, everyone will start in like unverified and then rejected, verified, et cetera., but this should be pretty fast. And, and I love building, you know, stuff like this is a little easier cuz it's internal, so you can kind of iterate on it. It doesn't have to be as pretty and perfect. Um, but that's what we're gonna do tomorrow. We're gonna, we're gonna build a queue. We're gonna do the auth. You're gonna see the list, download those docs, you know, approve, reject. And then, you know, of course, uh, uh, you know, the email that, you know, the investors will get. And then finally, we'll have to do this sort of PDF generation, right? So this will also be kind of a— this is an unknown. I don't know exactly how I'm going to do this, but generating this PDF with their information right here and everything will be the next— will be the thing. And then that's that.
And let me just move that there.
And I don't know why I have this.
This is kind of redundant.
Um, and then yeah, we'll try to do this thing. I'm, I'm, I'm excited about the potential for something like this. Um, but this might be like, uh, another weekend or two weekends from now or something like that.
We'll see.
We'll see.
Um, but yeah, making good progress, making good progress. Um, about halfway done and we're a day into this thing, uh, 2 days. So we'll see, we'll see how it goes. Thanks everybody for, uh, for tuning in and I will be ending this.










