So yeah, I just wanted to give kind of like an overview,
like Flutter flow, but also how we're using it.
And so when you come in here, we have a team account.
So I'll make sure you have access to the team.
And what will happen is we have to share each project with you.
So each app that we build for our clients
is its own project.
And this is kind of what we need the most help with,
is that let's say this was the very first one we did,
Brilliant TV.
And so that is the very first version of building it.
We built 100x, which was more improved.
And then we've done these other ones.
And the Wisdom app is kind of like our best version yet.
And so all the upgrades are in Wisdom app.
But for example, not all the upgrades
have been moved down into Brilliant TV.
A lot of the work is like, that's
what we're going to do today, is that all the authentication
stuff that's over in Raising Royalty is outdated.
Not outdated.
It's just we came up with a much smarter way to do it.
And so I'll bring up this as well,
because I think we have, let's see here.
This is just Mux, Firebase token.
And so you can see here the way that we've set this up
to do an actual token here.
This is something new that Lucien added.
So we have, when someone logs in,
they actually get a Firebase token.
And then that is then stored over in Firebase.
And then it can access it a lot more.
It's a lot more stable that way.
And what I'll do here is I'll just open this.
And then you have to actually go type this in.
It's not really a fan of having multiple windows open,
but we'll still do it.
Now, the cool thing is you can copy and paste components
across.
So I'll just kind of show you.
This is sort of the view that I spend most of my time in.
So I've got sort of the pages over here.
And then underneath here is the breakdown of how
that page is put together.
So we'll start with this entry page.
We've got a logo, a little container here.
And then if you saw, oh, container,
if I hover over here and I kind of scroll down,
see how it kind of highlights it?
So you can always kind of see, OK, there's the container.
It's got in here we've got a bit of text, which
is just static text.
Then we've got this email input field.
And then we have a button that says log in.
So that's going to execute something.
And here we've got another button that
says join without an account.
So that's the whole sort of structure.
If I were to hit Command-X, delete that or undo that,
I can pull that whole container out or rearrange it
on the page.
It's very drag and drop.
So if I wanted this, for example,
to be at the top of the page, I can drag that up and down.
It just sorts it here.
And again, you kind of know, even from Tailwind,
how this is structured.
Basically, this is a column.
And it's using Flexbox to organize this.
Yeah, so you could kind of use the start from a flex.
And then or you can have it all to the left or to the right
or centered.
So that's just sort of how the page is put together.
And what's nice is they give you sort of the,
you can jump between pages on this top part.
And then you can jump between the details on that page,
kind of on the bottom part.
It used to not be quite as easy as this.
But this is a nice way to get it.
Now, there's a lot of pages in here.
So I'll kind of go through them.
How do you link two pages?
Just wondering.
Yeah, so like, OK, so let's just keep going on this page.
So we've got our container.
Let's just see.
So that's the sort of like, I would say, the UI component.
It's like, here's how the is an image.
There's a stuff.
If I want to change the text, I can just come in here.
OK, so let's talk about logic.
So you typically attach it to a button, right?
So the button is going to fire.
And it's going to tell it to do something.
So we're going to go over to the actions here.
And so anything, like I can click on this
and go to actions and have it do something like,
hey, on, if I hit open here,
it opens up a little editor,
like on tap of that image, like perform some action.
You can even have it like on double tap do something,
on long press do something.
And that's just on that image.
So same way it applies if we want to do it to a button,
I click open.
And so it's very visual.
It's kind of like a mind map of like logic,
but you can visually see the logic displayed.
So like talking through this,
basically we'll just start at the top here.
It says on tap.
So when you tap the button, what does it do?
It checks, first it checks the conditional
and we can click on this and it can say, okay,
is login email address.
So is that field set and not empty?
So basically did someone, did they even put something in?
So I jumped back, like this, is this empty?
And they just hit find my account.
Like we need to throw some error or something,
be like, hey, you didn't put your email address in.
You know, that's all that does.
And if it does, if it's set and not empty,
then it's true and it goes down one path.
If it's false, we're going to do something else.
And here we have a little thing called a snack bar,
which just is a little pop-up that says, you know,
please enter an email address.
And you can, you know,
everything else down here is just styling.
Like you want the background color to be red.
We want the text to be white.
You know, this is what we want it to say.
And then it's going to be up for four seconds,
four milliseconds, 4,000 milliseconds.
And then it's going to just hide by itself.
So that's like just that little logic there
to basically validate that it's even filled in.
And then we go down like API calls.
So I'll show you how we set that up here.
This is actually on a different page.
And let's say, so let's say it's going to validate the user.
So now we can actually go back here
and we should have a valid user validation by email.
So slash user dash validation.
That's all we're doing right here.
We're basically calling this validate user idea.
If I click on it, you can see here it's, you know,
the base URLs, whatever that is, it's a variable.
And then we have auth slash user validation.
And I can just cross-check this
against my tribe documentation.
And so that sort of show you like how it's connecting
into the existing platform.
Then we can see here, like, it's going to be a get method
and we're going to give it past the email
and we need to pass the platform ID
and there's no authentication needed.
And then we should get something back like this.
Like here's the platform.
Here's the person's email.
You know, is there a Firebase set?
Is the password set?
All that good stuff.
And I can see here in the query, there's my email.
There's my platform ID.
And I'm passing these three variables into the call.
So I can create variables like this
and then pass them into the call.
Very similar to like, if you had a react component
or like a function and you were passing variables down,
you know, into that component, same kind of idea.
You can like pass three or four variables into the API call
and then it'll send it as part of the query here parameters.
So you can, and you can test this right here.
I can just do that and I can hit test API call.
And there you go.
So now it came back with a 200 and I can see the URL.
See, it built this whole thing out.
Slash all, question mark, email equals Bruce.
Platform is three.
And the response comes back like this.
So I get my user ID, my name
and all those different things come back to me.
So back on this thing, that's what this call does
is it says like, okay, I'm passing the email
and the email is the, like the input field,
the thing the person just put in.
You can actually grab it from the state of that widget state.
And so I would go in here, you can choose widget states
and there's only one here called login email address.
And then you can even have default.
We don't really use that.
I can confirm.
And then base URL, we actually have a local state
where we can set the base URL
for all API calls in one place.
And this is very helpful when I wanna duplicate
this whole thing and paste it into another project
because it's gonna use whatever that client's
new base URL is.
So we don't hard code.
each of these calls, we leave like a base URL,
which is exactly how like it works right in a regular API.
But that's something where like,
we've kind of built it a little bit smarter
because we're like, hey, we have to copy this,
we have to copy this whole page
and paste it into someone else's project
and it still should work.
And so the same thing happens here.
Platform ID is set by a local state platform ID.
So, and those are set here.
So just, if I give you the quick tour here on the left,
this is like Firebase database
and then you have your local states here.
So these are all, so if I search here for like base URL,
you can see here it's HTTPS app.wisdom.ly.
And if I looked for platform ID,
I can see platform ID as an integer
and it's set to three.
And this is where you would actually change this.
You could just change it to four or five right in here.
And that would update the whole app
in this little variable app area.
So it's called local state.
Luchan, that drives Luchan crazy
because it's supposed to be called local storage
is what it should be called.
But basically it's the default when you load the app,
but it stores it in local storage.
So, cool.
And then going down here,
like this right here was the local states.
And if I go down to the next one,
it's all of your API calls.
So all those calls get saved
and all of them are pretty much set up here.
And then we've got things like media.
So if you do wanna upload a logo or something,
you can host it as part of the app,
the actual application.
So when the user downloads it,
the image, for example,
is already part of the app package.
Then we don't have to like call that externally.
So we generally don't use that,
but for some logos and stuff, we bring that in.
They also have like a bunch of custom functions.
And so these are things that we've been writing
over the last four or five months
when we need different things.
Some of them are really, really simple.
Is the content type video?
And then it's just like, hey, is it mux?
Then show true.
Is it Vimeo?
So true.
Is it got an MP4?
Then say true.
Is it contained YouTube?
Is this a video or not?
And then all the other alternatives,
it basically checks that.
So this is a little function.
We pass in a parameter called
whatever content type or whatever.
And that just, we pass these arguments in
and then it figures out.
Now this is all written in Flutter,
but you can kind of understand it.
It's very similar to JavaScript in some ways.
Yeah, I can definitely see, yeah.
Yeah, so if you have to come and change it
or add like a new option here,
it wouldn't be too difficult.
No, no.
You have to duplicate this line.
This one looks pretty simple.
Yeah, so it's a lot of very small functions.
Like a lot of them are very small.
Is this restream?
Like it's just straight like,
is false this restream true?
Cool.
So some of them like,
there's some that are like a little more elaborate
about like image replacement paths and things like that.
But, and I can see this is actually wrong.
Okay.
Yeah, it's the wrong URL there.
But some of these are not,
not all of them are being used.
Some of them are just in here, so.
Can you use the function for like every project?
Or that's just for wisdom, like?
This is, yeah, so that's the fun part
is this is just for the wisdom app project.
Oh, the 400, no, oh yeah, 43, sorry.
Okay.
Yeah, so you'd have to like copy this
and then move it.
If you wanted to move a function,
you'd have to copy and paste it.
And I think eventually they're gonna have
like shared component libraries is what I hear.
So that, yes, you could have like a library
of components for our company,
of which we could like import them to five projects.
And if we update it on one, it like updates it everywhere.
No, that'd be pretty cool, yeah.
Yeah, and same for, so there's functions
and then there's components as well.
Functions, and then there's components as well.
So little things like a little pop-up, right,
that someone fills out.
Let me see if there's a better one here.
So here's a little component that when we want
to edit a post.
It pops up and it says, hey, do you want to unpin this?
Do you want to report the content?
Do you want to delete this post?
And so this is a little component
which would be amazing if we could save this to a library
because every project will need this.
But what we do now is we go in here
and you can copy the whole component
and you can just jump to a new tab and hit paste.
And so it's not too bad.
Yeah, it's not too bad.
Yeah, it's not ideal.
Yeah, especially if you need to change something,
like you need to modify one of the components.
Exactly.
You need to modify them all.
So let's come back to this thing.
Let's keep going along that thought.
So we open this up.
So this essentially is the call.
And then I was just showing you the local states
and how that actually gets in there.
And then we call the action, the response here,
we call it validateUserCall because on the next one,
we're going to say, hey, did this call succeed?
Was the API response a success?
Because then we can catch it and say, OK, cool.
So it was a success.
Now move to the next thing.
And so we want to, in this one, say, hey,
is the password set true?
And so the way you can do this is you can actually connect it
to, and I'll just delete this and start it again.
So I can actually say output actions.
And then there's my validateUserCall.
So I can say, I want to check the response from this.
And I want to actually get something
from the body that came back.
And then here I can choose a JSON path.
And then under name, you can customize this
with a JSON path selector.
Or we have these ones saved.
So I can just say, is password set?
Hit Confirm.
And so that way, if it's true, it's going to do one thing.
If it's false, if it comes back false,
then it will do something else.
And so if it's true, so that logic is like, OK,
they put the email in.
It went true.
They got this back.
It was a success.
Their password is set.
And then we have an action that is navigate to some other page.
So you can say, navigate to, and you
can pick which page you want to get to from here.
Yep.
That's very cool.
And then in addition to that, you
can kind of go another step further.
You can actually pass parameters into the next page.
So there's kind of local state, local storage stuff.
Or I can have a page parameter.
So I can pass into the page, I could pass the email address
so that when that person gets to the next page,
they don't have to put their email address again.
We just checked it.
We already know they have their email.
Let's pass it back to them so it's prefilled for them.
And then we also know their name because in the response, part
of that call was to get the name back.
So we know that the person's name is Bruce.
So just to make it a little nicer, we say, hey,
welcome back, user name.
And then that's how we're doing it is we
pass to this page, returning user.
And you can see it says here, welcome back.
And then it's got the name there.
Yeah, and you can see this is just a very simple tool
called combined text.
So we can say text block one is this with a space at the end,
name, and then an exclamation mark.
So we have three little pieces.
We're combining that text.
So it's like static text, variable, static text.
And you can kind of rearrange these, which is very easy.
Yeah, just drag and drop, yeah.
Yeah, and then here, we're saying
we actually disable it from editing at this point
because we don't want them to.
We've already validated this.
So we have an input field here.
And I just blocked it.
So they can't actually edit it here.
And then we also want the initial value
to be the page parameter.
So I click on this.
You can see there's a parameter here for email.
And if I click off of everything,
or I just click to the very top of the libraries,
you go to the very topmost component here,
you see there's page parameters.
And I can choose these.
I have a string called email.
And I have a name there as well.
And I can just easily add another one
if I wanted an image path, or a document,
or all kinds of stuff.
And then you just want to remove.
that. So that's where like some of this we're going to I'm going to do some of this here
in a second and we'll kind of get into more of a project of this. I'll consider this sort
of like chapter one of like where stuff is. And so let's say it like goes through that
process. Let's say we go to returning user. We click sign in. So let's just open this
up and this actually gets much more simple now because we're going to use the back end
call called sign in. So just jump in back over here. User sign in. It should be slash
off slash sign in and we're doing a post here with email password and platform ID. And we
can see here like email password base URL of course and then platform ID is all coming
into that. So those are all the parameters we need. Yes. And then we have that response
says sign in response. And then again we have a little succeed and this one says hey you
know please check your email if something went wrong or if it worked we want to go ahead
and log in. And the way we do the login is we actually use this JWT token. And this is
something new that Luchin actually added here and you can see custom JWT token down
here. So if a platform is connected to Firebase we also contain this custom JWT property.
So it's a token that basically says hey you're logged in and keep all your information. So
we don't have to. The authentication is essentially happening on Firebase but it's it's the
permission to use the page is coming from the tribe. And then we have like a user collection
here where we we actually create that user on the Firebase side as well. So we store
their name their email we store their tribe token all that good stuff gets stored. And
then on this once it's logged in you can see it just sort of ends. And then well how does
the user get to the next screen. Well this is where you actually have something here
for authentication. So when someone's at an initial page there's this redirect page and
then when someone's logged in it automatically immediately redirects you to this page called
logged in redirect. And so once I'm authenticated the app Flutter by itself is going to take
you into the logged in page. You don't have to tell it to go anywhere. It's going to say
oh this user is logged in. I need to get this person to the first page where we set this
over here. And this is where we get a little sophisticated. And this is a definitely more
of an advanced part of Flutter flow is we now have this little page which is just a
loader little thing spins and it says accessing wisdom you know dot dot dot which is just
kind of a placeholder. And what we're doing on this page is we have something at the very
top. So before I triggered an action based on a tap but this you can actually trigger
actions based on page load. So when someone arrives here I'm going to go over here and
you can see there's actually 12 actions happening on this page. Well what this is is think of
this like air traffic control right. Like this is the all the in and out of the switchboard
of like we send everybody here. And this page basically checks a bunch of stuff to
see like first off is the user logged in. If they're logged in true then move to the
next thing. If they're if their tribe token is set in the database great moves the next
thing like check their status to make sure their account still exists you know and that
the token is that is valid. Has their user ID even set true or false. You know it builds
this out. Then it says like OK if so like go get the list of groups and store that into a
local state. So we store the user's groups and then we and then we navigate them into
the group. So we actually grab this and by the time they load the next page which would be
this one here the list of all their groups. And so while we're doing this let me go ahead
and it's going to hit run up here and that will actually fire up the app and we can play
with it in a test mode there on the browser. So you can actually see some of this working
a little bit but it takes about two to four minutes here to load this one. And I'll also
show you like there's two modes so there's like a run mode and then there's a test mode so.
The run mode is you build it and it basically creates a build of the app and then it gives you a URL and you can use that link forever to keep testing it.
The test mode is really smart. This is actually, if I was working on this page, I would use the test mode and it does a quick like three minute build and then every time you make a change, you just go to the test mode and hit rebuild and it takes maybe like 15 seconds and then it's updated.
That's smart.
Yeah, so that's like the way you'd want to like go back and forth and test it.
So I'll let this build on another tab while we do this.
So this dumps you then into the group list.
So what happens is when someone leaves the app, you know, goes away for a day or two, and then they tap back into the app, the Flutter flow authentication flows this way.
It goes, it already knows, like, are they logged in or are they not?
So it sends them immediately to the logged in page, which is the redirect.
So then we go to kind of this switchboard of a page, which basically says, like, where is this, like, how set up is this user?
And if so, like, essentially what we're doing here is we basically log them out if something's not set and we ask them to log back in.
If something fails, we run through a little process of updating users or things like that.
And some of this may be redundant, you know, now, but you can see it's just on page load, run all these things.
And so this is built and I'm not going to rebuild this today, but I am going to move this into a new project.
So that's probably what we'll spend most of our time doing.
Okay.
Yes, that gives you a little bit of a sense of, like, just the authentication.
And honestly, in many ways, that's probably the most complicated part is just getting to that authentication piece.
So is there any questions on that so far?
Not too many.
This is like quite a lot, actually.
But I am really impressed, actually.
There's so many possibilities.
Yeah.
So we'll have to, like, play around to get more familiar, for sure.
Sure.
Cool.
I'm going to...
Let me...