Transcripts
1. Intro: Class is for everyone
who wants to learn about creating a
full SAC application. In this case, MicroSAS
with Next JS. You learn how to work
with the router, make calls to database, and set up and implement third party services like
clerk for user management, stripe for payments or Super
Base as a database provider. Don't forget to check out the class project and
challenge yourself by creating your own MicroSAS
after taking this class. We will create a library
website featuring SAS or more specifically
MicroSASPduct from scratch. We will start by
preparing the UI, then move on to adding
functionalities needed for Live SAS product. This includes setting up
authentication using clerk, establishing a database
connection using Prisma ORM, and storing data in suba baase, which I will be using
in this tutorial. But don't worry. You don't
have to use SupAbase. Since we are setting up
connections with BismoRM, it's incredibly
easy to sweep out SupABse for any other
database of your choice. We will also integrate
Stripe to set up a subscription model so users can access the product
after subscribing. The goal of this tutorial is to help you gain hands
on experience, building a SAS
product and have one in your hand that
you can just modify, customize, adapt, and use. And in the end, we will deploy our application to HID live where I will show
you step by step how to make everything
work together. Without further ado,
let me walk you through the demo and then we will
finally start building. We will start on page
as a new user and we are starting there with Nov
bar where we have a pricing, the team setting, and
a possible sign in. Then on the page, we
can see that we have some sale for the
starting price of our product, name
of the product. We have there get started, and then the three easy steps, how to use our product. If you will continue
down the page, we will see there a
demo of our product on this animated picture
that is changing the rotation and opacity
as we are scrolling. Then we have frequently
asked questions section where we will click
on the question and the answer will be displayed. Below is a pricing section, and there you can
buy the yearly plan or monthly depends
how you set it. And below is this
animated section with some already done thumbnails being rotated there in a circle. And now let's continue
to product itself. We will try to sign up. Then I will continue
with Google. After we sign in, we can see that we are not
subscribed yet, but also new items
in our Navbar. These are for the
product itself, pricing and also
profile where we will set the channel name that
we will use in the product. Let's click Subscribe. There we will fill in the data. And we will get onto
payment successful page, and there we have our product because now we are subscribed
to the application. There you can see we can set the title for the video card, then the tab itself,
and the channel name. For the channel name,
we will actually go to profile and as we will
now be using this, we will set there our
channel, something like this. I will submit it. Now I
will go back to product, and there you can see
I have it prefilled, and every time I will look into the application, I
will have it there. Now that's the previewer itself. I will put there
thumbnail for the title. I will also put there something, and then I can see the video
card with the thumbnail. Now I can randomize the order, and also I can change it to
Tablet View or mobile view. And if we would like to
manage the subscription, we have that button
that will redirect us to Stripe where we can
just simply manage it. And that will be it,
simple functionality for MicrosAS with one feature
to test out the product. And of course, if
it's successful, there can be more and
more features addied. That will be it for the demo, and without further ado, let's finally dive into the code and bring
this project to life.
2. Setup: Our folder, we will start
with opening a terminal and pasting the command for
creating next application. There as we are
already in the folder, we can do there just the dot, head enter, and it will
install the necessary things. We will proceed with Y. There we will do
yes to tailwind, no to source, yes to
a router, no to As. Now we will just wait
a bit and we can continue with setting the
theme for our application. I prepare the team
for our application, and you will find it on this Gita link that will
be in the description, and there we will start with taking Globus CSS
and tailwind config. If you don't want
to go to any link, I will show you the code
and you can rewrite it, but it will be a bit tricky. Let's start with taking this tailwind config
dot Ts, copy paste. Go to tell and config
dot Ts you have there in your app and just paste
there the wall code. Now I will go over the wall code in case you for some reason, don't want to copy paste it
and just want to take it. Now we will go back to the page. We will go into Globals dot CSS, and we will put it into
our app, globals dot CSS. What we past it there as a
light team and a dark team, and then one more thing. On Git up, you will now
take layout one dot Tsix. Now in layout Tsix there, you will paste there the wall layoutTSix from Layout one
you took from the Git. And why do we have
the layout two? On layout two are some things that are
not yet implemented. So we will take
Layout two in a few, I think, in around 10 minutes. I think we can now do NPM run depth and start developing
the navigation bar, which will be the first
component we will do. Now we can see first
error on our page. We are missing some library. We will just open another
terminal and we will do NPM. And this tailwind CSS
animate, we will hit Enter. I will install the library. Now our page will work. You can see our page is currently having the
next J template. We will change this really soon. Now we will start with
the navigation bar. Let's go to our app folder, and inside this app folder we can create components folder. Or what we can just do is that we can start
loading some components. The command for adding these
components is real easy. You just need to
do NPx, shed CN, at latest, at, and now you
will just type the components. What we will use is a button. There we can do, New York neutral CSS
variables for teaming. Yes, now it will be created. Then also, we will
be using card. Then we will be using input. Then we will be using label. We will be using scroll area. And we will be also
using text area. Now, as we have it, it created component folders for us and also it created a lip folder for us with this utils dot Ts. Lip folder, this is
like a toolbox that holds the important tools and helpers for
the wall project. And in talking
about utils dot Ts, this is therefore combining
CSS class names for styling. Into this lip
folder, we will also add later helpers for database, for example, seeing these
components and UI folder, we have the het CN components. If we will click
on the components itself though, and there, click on a new file, we can
create there, Navbar TSX, and we will have the
separated UI for the ChetsN components and just the components
folder for our Navbar, but everything is wrapped
in this components folder.
3. Navbar and Theme Settings: Inside our navigation bar, we'll start with us client to define that this is a
client component and we will import link from library
that is called nextink. We'll start with doing the
export constant Navbar. And we will be
returning navigation. And for this navigation, we will start with
background to background, which is the background
that we defined in our team and border bottom. Then inside, we will do
div and in this dip, we will set some maximum weight. I will do seven Excel. I will center this and
background green 200, so we can see where it
actually is on our page. Of course, we need to
add to the layout. Now we have their Navbar. We can copy it. Now let's go into the root
layout, which is this one. And there we can
start typing Navbar, hit Enter, and it
will get imported. Now we will save it on our page, we'll be able to
see it really soon. I will just put there
something and you can see on the top there the
green background, which is our navigation bar. Let's fix this. Now
we will continue. We will set there flexbox
layout, justify between. That means we will have
even spacing between our elements and height to 16. Inside this div, we
will create the link, and this link will be
containing our logo. We will put there just SAS now, and there in the link, the HRF will be to lending page. For our case, there
is no route to this. It's just slash that will
get us there to root page, and there we will put some bedding text three
Excel and font Bum. Then below, you'll do a
conditional rendering, and we will ask I signed. And in case, yes, it will render something there. And in case, now, it will render other thing that will be on the
false position. Now to mock this because we currently didn't yet
implemented the ALF, I will put the const is signed, and currently, I will just
hardcode the true value. But later this will
depend on other factors. Currently, it will
always rear the true, but we can also
change it to false, and for testing purpose, we will do it now before we implement the actual
authentication. In case this is
true, it will render the link to our
actual application. We can just take this link. We can call this product. There it will get user to
dashboard page and right below, he will be able
to go to profile, which will be under
dashboard Profile. Now in case he is not signed in, nothing will be rendered. That means we will put
there false value, you can see the items
will disappear. Now let's take this link, put it below this
conditional rendering, and this will be
linked to pricing, and the pricing won't
be below dashboard. It will be accessible even
from non authenticated users. So it will be just
slash pricing. Then what I will do
is that I will put this wall conditional rendering
even with the pricing into one div because I would like this to
be in the middle, how this will look like, is that as we are using
justify between, we will first have
the logo of our SAS, then we will have this div
where will be pricing. Or if user will be signed, there will be product
profile and pricing. And below, we will have
a div and in this div, there will be setting
of the Tuggle that we currently don't have,
but we will edit later. For now, we can just
put a placeholder Team tagle but it's
really for us. This will be deleted
a bit later. And now we will again do
the conditional rendering. We will use this as signed
constant we have there. And in case he is signed in there will be the
sign out button. And in case he is not signed in, there will be the
sign in button. This will be changed for
the actual buttons that we will get from the library
of our of provider. Now for the styling of
our navigation bar, I will just put the background
grade to 400 for a while, because we currently
still don't have the team there for this div. I will put space x22. Then for the text, we know that text large will
be enough for us. Let's just delete text sizing
from everywhere there, and we will put it
into the wrapping div. Let's go there to this div
and put the text large. And also next to
justify between, we can just add items center, save it, and it will be
nicely centered like this. For the navigation bar,
I think that's fine. And what we will do is that
after we will do the tagle, we will put it there
instead of displayholder, and after we will
implement the O, we will put it there instead
of the Sigou and sign in. Currently, I will also
delete this background. Now to add the team, we will execute steps we
can find on stsn.com. You can find it there in search
documentation, dark mode, there you will select Next Js and we will just
execute these steps. First, we will install
the next teams. Let's open the terminal. Do NPMI. Next Teams, I did it twice because I copied it, but it
shouldn't matter. There, you can see
that we need to create Team provider TSX.
Let's copy this code. There, let's go to Explorer and components. Let's
create a new file. Team provider dot TSX, paste the code there, save it. Now on the page, let's continue. This is
what I talked about. We will use the Team
provider wrapper, and they will go to the Git upp. There you will go to Layout two. You will take this code
and you will put it into the layout the TAix
in app folder. And now we ddt their
Team provider, so it looks like this. Also we edit font heading
and font body for our font. There we are setting it
in a class name and body. There we are using the
team provider and we are wrapping the
Navbar with children. And what we will do next is that we will go back to Chet CN. Now we can check this step and we can continue
to add the mode Toggle. There we will use this
one, and in a code, I will click on copy, and we'll be creating
a toggle component. There in our ID, I
will go to components. I will create a new file, and I will put the
Team toggle, Tsix. And inside, I will
paste the code. We are missing drop down menu. How we will fix it
is that we will do NPX ShetCN at latest
at dropdown menu, and it will install
this component from the het CN library to
our UI folder there. Now let's click again
there, weigh the bit, save it, and that's it. And finally, what we
can do is that we can use mode Tuggle in our Navbar because we
have the export there. Let's go to our navigation
bar there to placeholder, where is the team tagle
we will do mode Tuggle. It's not named
Team tagle because the export is just
named mode Tuggle. And there, we will
now go to our page, you can see we have
it next to the sin in button and change to light, it will be using light mode. To dark, it will be
using the dark mode, and to system, it will be
using the system mode set. Now let's go back to Navbar, and for this DIF that is holding these sin Sinnot buttons and mode tagle we will add
also space x to four. And also flexbox layout
and items to center. That's it for the navbar,
and we will come back to it after we will do
the Of provider.
4. User Interface: You can start working
on our lending page. First thing, what we will
do is that we will delete this next GS template and
we will start with DIV. In this div, we will use BG background and
also text for ground. Inside this div, we will create a main tech and inside
this main tech, we will put the classes
of container, AMS auto, bedding x two, four, bedding from top to 12, and also text to center. There in the main, we will do heading one. We can put there for now some
placeholder like micro SAS, tutorial, and we will add some styling to it that
will be text for Excel. On medium screen, we will
increase it to text six, Excel. We will do the font bolt
and margin bottom to four. Also below, I would
add paragraph tag, and there will be the
description of our micro sas. For now, I will ada
just this text. And for the styling,
I will ada text Excel on medium text to Excel, margin to bottom eight, maximum width of three Excel, and a mix Auto. Next thing, what we
will add is a div. In this div, we will
have two buttons. The button will be the
one we imported from Chet CN. I will
import it like this. And inside will be view pricing. Then below, we will
have this button again, and there we get started. Actually, let me maybe change it to get started
and view pricing like this. Styling for these
buttons will be flex, justify center and space X for because these
buttons will be next to each other
and below this dip, we will have an image. And in this image, we will
have the closing tag there, and it will have some source and d and also some class name. For the class name, it
will be width to full, height to auto, and
margin from top eight. Why I'm using this image and
not image from next image, I can actually delete the
input from there is that because I will be using
their source from URL. For now, we will leave this empty because we will
style it later after we will have our product
and we will put the picture of our product
demo to this landing page. Currently, we will leave the
landing page like this and we will finalize the styling
later even with the image. Before we move on, last thing, what we will do there is just variant and there
we will do outline. Now if we will save it, you can see how it will
look on our page. And now we can move
on with creation of UI of our Micross application. Let's continue by creating
Dashboard folder. We will click there on app, there on a folder, and name it Dashboard. Inside Dashboard folder, we
will create page dots six. But also, we will create
there another folder, and that will be called Profile. Inside this profile folder, we will create another
page dot Tsix. We will create also
pricing folder. That won't be in Dashboard
though, that will be in app. There in app, we will
create new folder pricing. And in this folder, we
will create page dots six. How this will work is that when we want to go to Dashboard, our URL will need to
look like dashboard. For profile, it will be slash
dashboard slash profile, and for pricing, it will
be just slash pricing. In our dashboard page, we'll define the main dashboard component as async function, export default, async
function dashboard. And there for now, we
will just do a return. And in this return,
we will create a paragraph tag with
are Not subscribed. And below, we will do a link. And to this link, we
will add subscribe. Then we will do HRF to pricing. Then we can make this
one liner and we will wrap this into button
that we imported from Chet CN. Now let's put it there, save it and it will be
on our dashboard page. By the way, let's do this also on the landing page
where I forgot to do it. There we will just
make a link with HRF. Dashboard inside, I will
put this get started. I also need to import
it on the next line, we will make it as pricing
with HRF to pricing. I will go to our page and we
will click on Get Started, we will get to Dashboard. There we will click
on Subscribe and we will get to pricing that
is not yet defined. Let's stay on the dashboard, and there we will now make
the styling for this. You are not subscribed. Text, I will add the Flexbox layout with flex direction Colum
items to center. Justify center,
bedding to eight, round it, large
and shadow medium. Now I will save it for
the paragraph tech. I will add text large, margin bottom to four. Maybe I will do text
Excel, actually, and margin bottom I will do 26, and that will be as
just some initial text for the dashboard when user
will be not subscribed. But of course, there will be
a lot of back end to this. What we are missing is a profile page and pricing page UI. Let's do the pricing page now. We will again export default acing function
called pricing. Inside, we will do a
return, and in this return, we will create a div
and in this div will be first heading one,
subscription plan. Below this heading
one will be a div. And in this div will
be heading two. You can just do full access. And below, we will continue with paragraph tech access
to all features. Then with another one that
this will cost $10 per month. Then there will be some
conditional rendering. We can actually g this
also is subscribed. There will be some
form in case he is subscribed to manage
the stripe portal, and in case he is
not subscribed, there will be some form for the creation of
the subscription. Currently, this is subscribed, will be always true or false. And after we will do
the stripe integration, this will depend on the status of the subscription
in case it will be active, this will be true
value, in case not. This will be false value. Inside this form, we will put a button And this button will be managed subscription because when a user
will be subscribed, there's no reason for
him to subscribe again. He will be just redirected to a stripe portal where he can
cancel his subscription. Type of this button
will be submit, then we can copy this and put it there into our form below, and this won't be
managed subscription, but it will be subscribe. Let's take a look on our
pricing page. We have it there. Now let's add some styling. Let's start from the top with
maximum weight to Excel, and mix Oto, BY
eight, and Bx four. Then we will
continue for heading one with text for Excel, for extra bolt tracking tight, and on large, we will
increase this on text five Excel and march
into bottom six. Now for this dif, we
will do rounded large. We will set border and
also background card. Then text card, foreground. Some shadow for the light mode, some bedding, and
some bottom margin. Then for the full access, we will add a border to bottom, then bedding to bottom
two, text three Excel, font semi bolt, also
tracking tight, and margin bottom four. For access to all features, we will add leading
seven for the price. We will add text to
Excel and font bolt. And for the heading, actually, we will delete this
margin to bottom, and there we will
do space Y four. That means also we can delete
margin to bottom there. Now let's save it,
check our page. And on the pricing,
we can also add which features will user get
after he subscribes. Currently, he is not subscribed. We can also set data
subscribe to falls. But as I thought, this will be changed with the packend
we will code a bit later. Currently, this will be
for the subscription plan, and we can continue and start
with the integration of some third parties we are using and start coding the
packend for our application.
5. Clerk Setup: We will integrate
user management with Clark and you will sign in, then go to this dashboard. There in our applications, we will click on
Create application. For application name, I
will select SAS Tutorial, and next to email, I will
have also login with Google. I will click on
Create application and now I have there a guide
how to do this with nextJS. First, we need to install it. Let's open a terminal, past the command there and hit enter that will
install the library. Then we have their
environment variables. Let's click on Copy. And in our folder, we will create a new file
in the root folder, and that will be called dot NF. Also, we will go to Git Ignore, and there below f the local, we will add dot NF itself. And now we will paste it there. Next thing, what
we need to do is to set this middleware Ts. Let's copy the code
and middleware file also needs to be created
in this root folder. There I will create a new file
called middleware dot Ts, and I will paste there the code. Then we can also
see the example of the implementation for
this sign in sign out, but we will from this take only the clerk provider and
put it into our root layout. And these buttons, we will
put the navigation bar. Also, then it's just
about NPM run D, which is something we
are already doing. Now let's take this clerk
provider Let's go there. There we will go to App layout. There we will wrap this
HTML into Clark provider. You should do it like
this and also import it. And now we can move to Navbar, and there we will use the
sign in and sign Out. If you want to
continue with a guide, you will click there and
continue to Next Jazz guide, and there is a documentation of the things we will do now. First of them is to create these folders for
signup and sign in. Let's go to our IDE, and there we will
go into the app. And the app we will create a new folder that will
be called sign in. There we will create
another folder, which will be three dots, sign in with square brackets. And inside this one
will be page dot TSX. Then again, click on a folder
and do the same thing, but for sign up, then again, sign up with
two and page dot TSX. Inside these two pages, we will put this
code for sign up. And then the second
one for the sign in. And I was referring to
these two code snippets. Then if we will scroll
down, we will take this. We will put it into our
environment variables. Then we will go to
sign in and sign up. And there after sign in, we will set attribute
with force redirect URL, and that will be to dashboard. Now we will copy this and we will go to sign up and
we will put it also there. This means that after user
signs in or signs up, he will be redirected
to his dashboard. And in the environment
variables, we are setting that when clerk will be calling
to sign in or sign up, he will be redirected
to these folders we created there and it will
handle it automatically. Now, before we try it, we need to put it
into our Navbar. Let's go to components Navbar, and there we will
use it instead of these sign Out and
sign in place folders. I will put the sign out button. Let's go to the documentation.
There we will take this. We will go back to our ID,
and we will put it there. And with Clark, we don't need
this conditional rendering because it has this text for this signed in and signed out. We just need to import this. Also signed in and
sign in button. And I won't be
using user button. I will be using just
sign out button. I will make sure the imports are correct and it
looks like the DS. And I think now we can go
to our page and we can test this. We are on our page. We are not signed in.
Let's click on it. We have their clerk. I will click on
continue with Google. We are logged in, and now if you click on sign
out, we will be signed out. We can again sign in
with another user, and now we can go to clerk and there we can
check our users. There in overview, you can see total users and resend
signups or sign ins. I use these two accounts. I signed up and sign in. You will have all
your users there.
6. Prisma Setup: Now let's set up
the database and we will start with Prisma ORM, and then we will
store the data in a super base which
uses Post grass SQL. If you go into Prisma IO, there you can click
on Get Started and you will get to
this documentation. You can click there start on scratch in case you want
to do this on your own. There, what we
will do is that we will use the first
command in terminal. Let's open a new one and put their NPM install
Prisma with safe Dev. You are curious
about more commands, you can do NPXPrismA. And that can give you some help. And now we will do
NPXPrisma in it, and that will initialize
Prisma in our repo. There we have it.
And in this file, we will be adding
models for our objects. In the documentation of Prisma, will click on Connect
to your database, there we have also documentation about how to connect this, and there we will also
install Prisma client. Let's take this NPM
install Prisma client and also we will put
it into our terminal. What this does is that this adds some special tool called
Prisma client to our project, and this will basically help us to talk to our
database more easily. Whenever we will make
some changes like adding new fields or tables, and we will run the command
and Px Prisma generate, it will update the Prisma
client folder with new code, and it will match
it to our database. In our case, it will
be super baase. This way, our application can use the latest
database changes. Prisma is really easy
to set up. This is it. And if we want to
just use Prisma and not use SupAbse and keep
the database locally, we could just change this to
file dot n for the source there and we can start writing our
models for the objects. But we would like to keep
our database on a server we will be deploying
this project in the end and it will
be accessible online. That means now we
will go and set up Supase and then we will
connect it to PRISMA
7. Supabase Setup: We will go to SupABse and
there we will sign up or login if you already
have an account or also you can basically
use Continue with Git up. There you will click on
create a new project. We will choose Organization. There we will select
project name. There we will
generate a password, and we will click on Copy. Save this password somewhere. We will use it in a while, select region, and then we will click on
Create New Project. Now in Super Base in
project settings, and there in database, we can get this
connection string. We will click on copy, and we will go to our
environment variables and we will paste it there. Now there into your password, you will paste your
password that you got from Superbase that will
look like this, but of course, this
is your password. Then take this wall string and put it into
this database URL. Now we will go on documentation called Super Base with Prisma, and there we can also see some next steps we need to do to connect this with Prisma. There you will find
these two strings. The first one will be
for the database URL. Basically, it's
the same we have. The only thing edited
there is after database name is this question
mark with PG bouncer. Let's take it and
paste it there. For the database URL, then your string will
look like before, but with edit question
mark and PG bouncer, we can delete this, and
there we will create a new environment variable that will be called direct URL. And that will get
the second string. If you will check it, it's the
same string uler Superbse. It has a different port. It's using 5432 and
the database name. That means we can go back to
our environment variables. Take this string. Put it there. Now we will delete this
up to this database name, which is Post Cress,
and we will change this port to 5432. Now we will save it and now we will go to
schema dot Prisma. And there, we will add below
this URL for database URL, direct URL, and we will set the environment
variable, direct URL. Now we will save it. And now we can start writing the
models for our objects. We will start with
model user for user, we will define ID that
will be of type string. Then we will define and it
will be ID, tech and unique. Then we will define email that will be also
of type string. It will be also unique. Then we will define stripe customer ID for later
implementation of stripe. This will be string
with question mark that will mark this as
optional field, and we will take it also as unique because we will have
only one kind of this ID. We will continue with name that will be also string
with question mark, and that also means it's
optional and it can be now and that will go
even for subscription. Now, what I did there
is that I said this as an optional relation
to a subscription model. Below, we will
create a new model and that will be
called subscription. We need this because we need
to track if the user is subscribed or not subscribed
to our application. There we will need stripe subscription ID that will be string ID, and unique. And we will use it
as unique identifier for the subscription. Below, we will need to add
more fields that will be status that we will use for
the subscription status. It will be a string,
then it will be current period start,
which will be date time, then current period and
it will be again datetime then created a that will be datetime and the default
value will be now. This will put for
our subscription, the datetime of now, which sounds obvious, but it's
just that straightforward. Then updated it. We will use this whenever
subscription will get updated. Then the interval,
then the interval if the subscription is yearly
or monthly, plan ID. If you have stripe plan, then we will save it
into this field and user ID or the user that
will have the subscription. Now, this will be string and this will be also string and
this will be also unique. Then we will create
a relation there to the user model that
will be done like user user and relation
with fields, User ID. References ID. Now in this terminal, we can do NPxPrisMa format. And if you will be
adding something, you can just do arrow up, Henter and do it again. And if you want to clear your
terminal, just write CLS. We can save it. And with this, we have the schema Prisma done. We will now hit
NPXPrisma studio, and it will open UI for us
where we will see this table. Let's now open N terminal
and do NPxPrisma DB push. You see it failed for me
and it's because I used the wrong password
there because I was showing you with
this example password, and now I will just put there the real password
from the superbase. If you forgot it, I will
show you how you can get it. There in database,
you will click on Reset database password,
generate password, reset it before, just copy
it if you want a new one, and then you will put
it there onto display. Now what we will do is
that we will put there in the terminal NPXPrisma
Migrate Dev. We will enter there we
will put some name for the migration and
wait for a bit. We can also do this
with NPxPrisma DB push. NPXPrisma DB push
is when you want to quickly push some
changes to your database, it doesn't crack them, and NPXPrisma migrate Def
will track the changes. When we will add some
fields or some model, we will have it cracked down. You can also see there
in Prisma migrations. There it is. I think
as now we did it, we can go to Superbse and
there in table Editor, you can now see
subscription user, and you can see there
all the fields. Now it's time to load the
user into our database. How we will achieve this. We need to use Clark webhook for this because when
user will again, then the clerk webhook will help us save the user
into our database. Currently, where user
web clerk logs in, is just saved into clerk. Let's now code the part
where we will fetch this.
8. Clerk Webhook: Open documentation of
clerk and we will go there to synchronize Clerk data to your application with webhooks. First step is to set up Engroc. This will help us expose our local server
to the Internet. What we need to do is just download Ngrog and
after you download it, you will open the
engrogtExA file, which will open a
terminal for you. And before downloading it, you need to login
on this ungrog.com, create an account there,
and then you will download it and open the engrog dot
Xfile which looks like this. There on the page, we
will go to endpoint. We click on Sarto tunnel. There we will copy this, and now we will go there
into our terminal. In this terminal, we will paste
this, but it won't be 80, it will be 3,000 as
this is our local host. Now we can see it's
forwarding it like this. If we will go into our
rock and hit the tunnels, we can see it displayed there. Next thing we need to do is
to create API web hooks. We will go into our
IDE there in app. We will create a new
folder called API. In this folder, we will create a next folder called webhooks. In this we won't create
Route through Ts. But first, we'll create
the clerk folder, and inside this one, we
will create Route Ts. We can also create another
folder in Webooks. It will be called Stripe. And in Stripe we can
also create Route DS, and this is something
we will set up later. For now, let's go with the
clerk for the next step, we already have these
environment variables. Only thing we will take
is this Webhook secret. Let's copy it and put
it into our N file. There in environment variables, I will put it like
this and save it. For the next step where the
middleware is being set, something we already
did, we have it there. If we will continue, now
we need to install SWIx. Let's copy it, go into our IDE, and then terminal, paste
this and hit Install. Now, if you start moving
to the next step, you can see that we are getting the route
for our webhook. We will click on a copy there and we will paste
it into our route. Let's go there into the clerk, route DS based the code there. And there in step seven, we can see that if condition, where if the Evans type is user created, something happens. We would like to use
this because for this, when the user will be created, we would like to call
the database section for creating the user
in our database. Let's go back to step two. In step two, you can
see that we need to update this Clerk dashboard
with our endpoint. We got from Engroc There
we will in our clerk, we will go there into webhooks. There we will click
on at endpoint, and there what we will do. We will paste this
URL from the Engoc. We will paste it
there. And after we will do API,
web hooks, clerk. And this is the endpoint
URL we should use there. And what we want to subscribe
to is user creation. We can put there
user dot create, and also we can leave the selected updated,
deleted, and so on. Let's click on Create, click on assigning secret
and copy it from there. Now go back to our IDE, go to environment variables, and we will put it on display
to our webhook secret. Next step, what we will do, we will go into our lip folder, and there we will
create a new file. This file will be
called db dot Ts. In this file, we'll basically create and export
a Prisma instance, so we can then use it
in our application. Let's start there with importing Prisma client from
client library. Then we will define a type for the global object
that will include the Prisma property
GlobraFPrisma, global as unknown as and there we will set
Prisma two Prisma client or undefined in case
it's not found. Then we will create and export
the prisminstans itself. There we will use the existing prism instance
in case it exists. Otherwise, we will create a
new Prisma client instance. And inside, we will configure logging to show
database queries. In case, we will have non
production environments, which is our case, we will save the Prisma
instance to the global object. Global for prisma Prisma
equals to Prisma. And last but not least, we will do export
default Prisma. Now with having this, we
can go back to web hook. There we will import Prisma
from lip folder DB like this. And we will move down. Now we can delete this part. And instead of this part, we will do the if condition with the checking if the event is
of the user created type. I event type is equal
to user dot created, then we'll do constant
ID email addresses, first name and last name
equal to event data. You will do Trikageblock. Inside the Strikageblock, we will write to save the
user to the database. We will do await Prisma
dot user dot Create. There we will do data. For as well, it will be ID, email to email addresses first from this array because on clerk there can be
more email addresses. First one should
be the primary one which we are interested in. Then first name and we are actually using name. If you check our schema prisma, what we'll do is that we
will create a constant above or that we'll just create constant in
the spray block above, name it full name and set it there that this should be first name in
case it's not there, we will just make this empty. And connect it with last name. Again, in case it's not there, we will make this empty and we will do dot
trim on the end. Now for the name, we will set this full name and we will set there a new value
in case it doesn't exist. We need the email and ID mainly. Main thing for us is the email. Below we can do
console log user with ID was inserted
into the database. And then in catch, we will do the error and we will put a
console error there in case this will fail
error saving user to the DB with the error, and we will return
new response with error saving user and
set status to 500. Otherwise, in case
this will go through, it will set the
response to status 200. Now we can save it and
it's time to test it. This is currently our super base or Prisma, doesn't matter. Now we'll click on sign in. And we will again use some of our accounts to sign
in. I can see I'm in. Let's check what happened
and nothing happens, that will be because our
user was not created. For example, with the user
I currently logged in, it was already created in clerk. What I need to do is
to go to clerk and delete the current two
users I have in my clerk. There in clerk, users make sure there is not a user you are testing
this webhook with. Let's repeat the
process, sign in. Now again, I'm in,
and it worked. I can now see my user
in a super baase. Of course, as we are
using Prisma O RM, it will be also in Prisma if
we will refresh the Prisma. Actually, if it's not in Prisma, just do in terminal Sutter C and then do NPXPrisma studio again that should
fix it for you. Then if you will go into Prisma, you can see the user also there.
9. Stripe Webhook: Now we will set up a stripe. First, you will login
or sign up to Stripe, and then in Stripe, you will create a new product, and there in the new product, we will go into developers there we will go into API keys, and there we will take
the publishable key. Then we will go to our IDE, paste it there, and we will
go back for the secret key, we will click on reveal
and then click again, so we will get it to clipboard, and we will paste it
into our dot Nf file, so into our
environment variables. I have the publishable
key and the secret key, I will put a name for these
environment variables. As this will be a public one, I will put the next public and then Stripe publishable key, and for the secret one, I
will put Stripe secret. Then we will go back
to stripe page. There we will go to Product Catalog and you can see I already have
there two products, but I will create a
new one with you. Let's click there on at product. I will put there
name of SAS product. I will set there a price
recurring and 1990 $9. It won't be monthly.
I will set it as yearly and there I will
click on at product. Now I'll click on it
that will get me there. From there, if you will click, you can copy price ID, and then you can save this in
your environment variables. You can see like
this. I put it there. And last environment
variable we will need from Stripe is the
Stripe Webbook secret. So let's prepare it there. This is not the secret
you should put in. For the secret,
you will get this actually generated
from the terminal. So what we need to do now, we will go there on web hooks. We will click on test
in Local Environment, and there we will get a
guide what we need to do in order to set up
the stripe for webhooks. So first, we'll need to download the client there you will select your system
for meets Windows. There I will download this
zip file from Github. You will unzip it, then you will open the folder, then you will open
environment variables in your computer and you will add a path to this dot
ax file there. You will open your terminal. You will write stripe there, and you will get
this information. That's how you will know you successfully
installed the client. There we will go
back to this page. Then we'll put there this
first command, stripe login. We will copy the URL. Open it there, there
we will see the word. We will click on Lo Access
and access granted. Now if we go back to that page, we will see there completed, then we will copy this command and we will
open there a new terminal. Now we will paste this to
forward events to our webhooks. What we need to do is that we will change it to
our local host. Also we will put the
API webhooks stripe. We will ad Enter with this, we will get the stripe
webhook secret. We will paste it
and put it there. And now what we will do is that we will just try
to trigger some event. We open your terminal
and pase there this stripe trigger
payment intent succeeded and hit Enter. You can see that this
tried something, but as we don't have any
code yet in this strpouttTs, of course, it won't work. Now what we will do
is that we will code this part and we will
make this work and then after we will again run this stripe trigger
payment intent succeeded, this
will work for us. But of course, we can trigger this also from the UI itself, where we will just try
to buy the product. For now, let's just go
and code the web hook. First, what we will do is that we will go into Lip folder, and in Lipfolder we
will create a new file. This file will be
called stripe dot ts. We will start there with
importing Stripe Library. And we don't have Stripe yet. Let's open a terminal, and
let's do NPM I Stripe. Now, it will be fine
and we can continue. We will create and export a new stripe instance with a secret key from our
environment variables. Let's type the export
constant strip where we will create a
new stripe instance. And as input parameter, we will send process dot dot
Stripe secret key as spring. Inside, we will put API version that we need
to set to 202-04-0620, and if this won't work for you, just check what the latest API version is and put it there. Also, I will set
the typescript to true to enable
typescript support. And we can see some error there. Let's put there the recommended one in case it will
cause any issues, we will fix it later. Now as we are testing it, having this in developer mode, we are including there
also a beta feature with dot Acacia and after we
will be in production, it can just be with the
actual API version. Currently, we will use this
beta feature to include also. We will continue with defining an asynchrous function to
create stripe checkout session. I will do the export constant get stripe session asynchronous. And inside, we will set
the input parameters. It will be price ID, domain URL, and customer ID. And its types will be string. Domain URL will be also string, and customer ID will
be also string. There we will continue like
this and we will open a body where we will create a new
Stripe checkout session with these specified parameters. I will create a
constant for session. I will wait stripe dot checkout
dot sessions dot Create. And there, I will set
customer for this session, which will be customer
to customer ID. Then I will set mode that
will be to subscription. Then I will set payment
methods types For us, this will be card, then
billing address collection. There will be auto,
then line items. We will set this to
price where will be price ID and quantity,
which will be one. Below, we will continue
with customer update, and there we will set
update of name to Auto and of address
to Audo also. And last but not least will be the success and Cancel URL. These two URLs will be there after user will
check out to Stripe, and he will buy the
product, it will redirect him to this URL. And if the payment will fail, it will redirect
him to this URL. And these two pages is
something we will set in a while after we finish
this stripe dotTs. The success URL will
look like domain URL, payment slash success and the cancel one will look pretty
similar to the first one, but it will be canceled. We will define these
pages in a while. Now below this, we will put return session dot
URL as string. That means we will return the
URL of the created session. What we also do below this
create checkout session is to define a customer
portal session. When user will want to
manage his subscription, we will create a portal for him, and when he will click
the managed subscription, he will be redirected to
Stripe and in Stripe, he will have the
subscription management. He can cancel the
subscription there and so on. Let's do Export async function, create customer portal with input parameter of
customer ID as a string. We will create a promise there. And inside, we will create a new stripe billing
portal session, constant portal session. Wait stripe dot Billing portal
Sessions Create there we will send to customer ID and return URL to something
similar like there. We will take this from our
environment variables, next public URL. In our case, this will be
local host slash Pricing. But after we'll
get to production, we will change this
environment variable of next public URL to the
actual domain of our page. Now, as we have the promise of a string there, we
need to return it. So we will return a string, something that is called
portal session dot URL. Now we prepared even
the create customer portal next to checkout
session we have there. This should be it for Stripe
Ds in our lip folder there. Now we can go to webhooks. In webhooks, we will go to
Stripe and in stripe there, we will open the route dot Ds we will start coding the
Stripe webhook there. There we can begin. First, we will import the stripe instance
from our lip folder. Let's do Import stripe from the lip folder there, then we will continue with importing stripe for
the typescript support. Then we will import the
Prisma database client. We have also in our lip folder. Then we will import
headers function from NextS so we can access
request headers. What we will do
next is to define an asynchronous post
request handler function. We will put there input
parameters of request like rec and it will be
of type request. There we extract the raw body
of the request as a text. Let's do constant body,
elate request, text. Then we will get
stripe signature from the request headers
and we will save it into constant
named signature. There we will do headers, dot get stripe signature, a string, and we will have it saved there in
this signature constant. Then we will declare a variable
to hold the stripe event. We will do ten stripe event. Below, we will create a Tricgblock In this
stripe catch block, we will verify and construct the stripe event using
the webhook secret. There we will do event equals to stripe dot webhooks
dot Construct event. And we need to put there as input parameters,
body, signature, and process dot N Stripe
webhook secret as string. In case this will fail, we will catch it in this block, and we will return
there in new response and set it to webhook error
and set the status to 400. Then we will create a
new constant session, and there we will
cast the event data object as a stripe
checkout session. Let's do event data object as stripe dot checkout session. To explain this, this
event data object is accessing the object property within the data field
of the stripe event. This object contains
the full details of the event subject. And what we are doing there is that we are
telling the typescript to treat event data object
as if it were type of stripe checkout session
and why we are doing it. For example, event data object could be a checkout session, subscription or invoice type, and typescript
cannot automatically tell which one it will be. And because it could
be any of them, we will define it as
stripe checkout session. Let's continue with handling
of the different events. First, we will start
with handling of the event called checkout
Session Completed. We will do their if condition and we will check
the event type. This one will be checkout
session completed as I set. First, for every event, we will retrieve the full
subscription details from Stripe and we will save them into constant code subscription. There we will await Stripe
subscriptions dot retrieve. And we will retrieve the
session subscription as string. Then we will find the user in the database using their
stripe customer ID, and we will save
it into constant user await Prisma dot
user find Unique, and there we will
just select where the stripe customer ID is
session dot customer as string. That means that will check
our database and find the user that has this
stripe customer ID. Now we will have it saved in the user constant,
and we will continue. We will check if the
user was found or not. In case he wasn't found, we will return an
error, how to do this. Let's grade there
and if condition with exclamation mark, user, this means that if the
user is not found, we will execute this code block, and what we will do there
is return new response. And in this response, we will put the message, user not found, and we will also put the status, and the status
will be set to 44, which is for not found. Then we will continue
with creation of a new subscription in case the user is existing and
everything is prepared. We will wait Prisma dot
subscription dot Create. And we need to create
there the data, of course, and the data
we'll be creating. We can also see in our
schema dot Prisma. Let's start there with user ID, that will be set to user dot ID, which is ID of this
user we have there. Then stripe subscription ID that will be set to
subscription ID. This is there. Then we will continue with
setting current period and we will set
this to new date, and then we will put
subscription current period end, multiplied by 1,000. Now let me explain this. As date constructor
expects milliseconds, we need to multiply
this by 1,000. Then we will save this date into our current period end and we will do the same thing
for current period start. Again, you date, convert
or first let's get to it, current period start, convert
to milliseconds as well. We will continue with interval. This one we will set to
subscription dot items, and now we are using data and zero to represent
the first item in our array. There will be just one item, and that will be the one
we want plant interval, then we will continue
with plan ID. Then we will with similar
style subscription dot items, data first from the
array, plan dot ID. And last but not least status, that will be just
subscription dot status. That will wrap the checkout
session completed event type, and below, we can start
with another one. We will create a if condition, event type invoice
payment succeeded. Now for this events type, we will again retrieve the full subscription
details from Stripe and save it into
constant called subscription. There we'll do Avade
stripe subscriptions, dot retrieve via session
subscription as string. Now we don't need to check user. We will just update the subscription record
in the database, and that will be it
for this event type. How we'll do it is
that we will do Awad Prisma dot
subscription dot Update. And there we will
select ones where the subscription ID or stripe subscription ID is
equals to subscription dot ID. Which data we would
like to update. We would like to update status,
subscription dot status, and also current
period with new date, and again, we need to convert this subscription
dot current period and multiply it by 1,000. We can move to
another event type, which will be the
subscription update. Let's do a condition
event type equals to customer dot
subscription updated. And there, again, we
will do the same thing. There will be constant
subscription, weight stripe dot
subscriptions dot retrieve session
subscription as string. That means we are
again retrieving the full subscription
details from Stripe. I could basically copy paste it, but let me just code it. We can do it again
for these two events. So you will remember
it for the next time. Now we will just update the subscription record
in the database. Then we'll await RsmA dot
subscription dot update, and we will do this
on records where the subscription is
subscription dot ID. And with data, we will do that we will set current
period end to new date. Subscription current period
end multiplied by 1,000, again, for the same reason. Then we need current
period start, which will be the same case, subscription current
period start. Then we will update interval,
subscription items data. It's repeating, I would say, it's just same
thing over and over again with setting
different fields and so on. Now we set interval, now
we will set also plan ID, subscription dot items dot data. Again, this is an array. We will access the first
item, plan dot ID. And there will be one
interesting thing and you can set it or you
don't need to set it. When a user will buy
the subscription, he has the access for one
month or for one year. Depends on what we will set. When the user will
cancel the subscription, he still has the time
that he bought left. For a month, if he
cancels second today, he still have 28 days. For a year, if he
cancels after one month, he will still have
11 months left. But what if you want
to set some condition that when the user
will unsubscribe, he will immediately lose
access to our application. This probably isn't
the best case or the best things to do, but we can do it. And in case you
would like to do it, I can show you how, and we can set it
for application also because it's
just easy to remove. If you just remove this one
line, it will be fine then. How to do this is that
we will do their status. And for status, we will do subscription cancel
at period end. And in case this exists, that means that the
user really canceled the subscription because
otherwise, this field is empty. And when this field
is populated, that means that he
canceled the subscription. If this exists, it will
execute this true position, which will be canceling. If this doesn't exist, it will execute this
subscription dot status. Whenever user will
cancel the subscription, the status will be changed
from active to canceling. And as we will be
checking on our page for the product access that the user subscription
needs to be active, then he won't have access to it because his status will be canceling instead of active immediately after he clicks
on Cancel subscription. I hope you understood this, and we will show this
on a real example. As we will be testing
the application later, you will see how
this exactly works, and you will also
understand better how to work with
these event types. And we will move
to the last event, and it will be customer
subscription deleted. Let's do if condition there. Event type, customer
subscription deleted. There we again, save to
constant name subscription, the full subscription
details from Stripe, await stripe dot subscription. Dot retrieve session
subscription a string. And there we will update the subscription record
in the database. We will await Prisma dot
subscription dot Update. And where, again, the same thing Stripe subscription ID is
equals to subscription dot ID. And on data, we will update status to
subscription dot status. I will wait for this event and below this event at
the end of this body, we will do a return
of a response, 200, which will be okay response, that will be it
for this web hook. The message will be
null in case and status will be just set to 200. You can see there the events. You can also now make
there some comments. It's definitely
handy for future, when you will be coming
back to this code, now we can test our web hook. Of course, we want
to test it on Y for now because we
still didn't code it. But we will open our terminal
and there we will do a stripe trigger payment
intent succeeded. That will run. Now
we will need to find this one exactly
and it works. That means the webhook
was coded successfully. There you can see we are getting 200 status request response, and now we can code DI and actually just go
through the normal process, then check if our
subscription is being set to active and also set the main product page and test the handling of displaying the content based on the
subscription status. Let's open the File Explorer, and there we will go to
pricing page TS six, and we will continue with
coding the back end there. Let's first do
there some imports. Next to button. We will also import the react. Then we will import Prisma there we have it in our lip
folder and dbdt TS file. Then we will get stripe session that we defined
in our lip folder stripe. We will get also the
stripe itself there. Then we will get unstable
no store from next cache, and we will use this
to tell Next Gs that we don't want
to cache some data. In our case, it will be data in G data function we will code. Let's do import unstable
No store from next cache. And then we will import also redirect from next navigation. This one will come in handy because we
will be redirecting our users in case he would like to subscribe and
he won't be locked in. We will redirect him
to sign in page. That will be for the imports and we can start with
the first function. Right below imports, we will do async function and we will
call it get the data. This will take user ID and take string or also empty value. Why is this important to also
check for this new value? Because if this won't be there
and it will be like this, whenever unlocked user will
get on this pricing page, it will fail, and that's
something we don't want. We want to let everyone on our pricing
page check the price. But whenever he will
want to buy the product, he will be redirected
to sign in. There we will do the
unstable no store. That means we are telling
NextGS as I mentioned earlier, we don't want to
cache this data. Why we don't want to catch this? Because subscription
status can change, and we would like to show the most update
information to the user, and that's why we
will use it there. Then we will check if condition if we found
the user ID or not. In case this will be false, we will return null, and I need to correct
myself there, user ID, even if the
user ID is null, but of course, then
we will check it and we will just return now. That means this function
won't return any value. Then we will look for a subscription in the
database for our user, which is this one user ID. So in case this
user ID will exist, it will just continue
with this code execution, and there we can create a
constant with subscription, and into the subscription, we will save RsmA,
do subscription, find the Unique, and we will select where the
user ID is user ID. There we would like status
and also user from user, we will select Stripe
customer ID like this. That means we will get there the subscription status and
also the stripe customer ID. Now we can continue inside the main component and we
can also delete this is subscribe In this
main component, we will start with
constant user ID, and this we will get from
off and we will save into constant user,
the current user. This is getting the user ID
and full user object data. It looks like we didn't import it. Now, it should be fine. We will also get the
user subscription data with calling the get data
function we just did. We will save it into
constant subscription way to get data with user ID. What we just did now
is that we quote this function that
we created there. We are sending there
this parameter user ID, and it will return for us this status and the stripe
customer ID of the user. Then we will create
another new constant that will be this is subscribed, and we will check the
subscription for status active. We have an error there and
that's because we didn't return anything in our
get the data function. We need to return
the subscription, of course, save it. Now it will work, and
it will work as before, but it won't be hardcdt anymore. We have there now this check
of the subscription status. This value will be true or false depending on this output. What we want to do next
there is another function, and this one will be
asynchronous function, create subscription. There will be create
subscription for this subscribe and then managed subscription for this other button
managed subscription. Inside this function,
create subscription, we will start with defining
this as a use server. That means we will tell Next JS to run this
function on the server. Below, we will check
for the user ID. And in case there is no user ID, we will use the redirect. We import it there, and we will redirect
user to sign in redirect URL pricing. Whenever he will click
on great subscription, which will be there
under subscribe button, he will be redirected
to this URL. Then in case we have user
ID and the user exists, so that means he signed in. We will save the database user, and we will await
ismadtuser dot find Unique. Insight where the ID is user ID, and we will select
stripe customer ID. We can do their
additional check. If we are not able
to find the user, we will throw an error. Let's do if condition. If database user is not found, we will throw new error we can do user or
database user not found. Let's do database
user not found. We know what happens
in case we will be checking our logs after
something will fail on our page. Now we can get the
user's email from Clerk. Let's save it into
constant email. There we will just search the user for primary
email address, and there we will access
the email address. This will be the primary one, and that should be always
there because when he will login through
Google, he will have it. And when he will login through email and password,
it will be there also. In Clerk he can have
more email addresses, but we will be accessing
this primary one. Then below as we have this in case user doesn't have a
stripe customer ID yet, we will create one, and this
will be basically something like signing up for a new service and
getting the ID number. In our case, getting
the stripe customer ID. There we will do if condition, and if database user stripe
customer ID won't exist, we will create a new
constant for customer, we will await stripe
dot customers dot create email to email. And we will update our database with the new Stripe customer
ID as we got it. Let's do database user, await Prisma dot user dot
create where the ID is in user ID or user ID
is in ID for data. Stripe customer ID
to customer dot ID. And select stripe customer ID. Now we can also
add some Consolog for us database
user database user. Now I missed something there
because I have an error. And yeah, because
I am not creating but updating the
data or the user. Then we will do the double check that now we
have a stripe customer ID. Let's do if condition database
user Stripe customer ID. In case not, we
will draw new error failed to set stripe
customer ID for the user. Now we can finally create
a stripe checkout session. That means we will
send user finally to the payment page of Stripe where he will be able
to buy our product. Let's do the constant
subscription, URL. We will await get stripe session there we will set customer ID to database user dot
Stripe customer ID. We will set domain
URL to process dot enftnN in case this
will be production. Let's use process dot
N production URL as String, and in case not, we will use HTDP
local host 3,000. And then price ID
of our product, we saved in
environment variables. We will do process dot
dot strip price ID as string and that will be it. What we are doing
there is that we are checking, we
are on production, this can be read from
this node N in case yes, we will set this domain
URL as the production URL. And in case, no, it will
just be for our local host, 3,000 where we are
running our server. And then after this, we will return, redirect
to subscription URL. And with this, we finish
this create subscription. What we need to do
below is to also define a function to create a new
customer portal session. There will be the
place where user can cancel or update
his subscription. Let's do async function,
create customer portal. And we will again
define the use server. And then we will check for the user ID in
case there is not, we will return
redirect to sign in, redirect URL pricing and this shouldn't happen because
we are having the check is subscribed and the user cannot be subscribed
when he's not locked in. That means when the user is not subscribed or not
logged in at all, he will see this
subscribe button. This subscribe button will
have OnClick function. This create subscription
where this check already is. Now it's up to us if we want to do this check also in create customer portal because
technically, it's not needed. Let's now create a stripe
customer portal session. We will create a constant
customer portal URL, and we will await stripe
billing portal dot sessions dot Create what we said there is a customer from subscription user stripe
customer ID as string, and also return URL, this will be there whenever
user will click on a B button in the
Stripe customer portal. He will be redirected there,
and this will be again, same thing like
before, rosst Noe N. In case, this will
be on production. It will execute this position in case this won't
be on production, it will return him
on local host 3,000. Basically, in case this
won't be deployed, and we will just have
it on our computer. This is a turn operator, that means this
is being checked, and when it is a true value, it will execute the
first position, when it's false value, it will execute the second position. Now there, in case this is true, we will set the
process dot Nf dot production URL as string. Now, last but not least, we will return redirect
to customer portal URL. Now we prepare these
two functions and we are ready to use
them at our buttons. Also, what we will do there
is a constant called B link, and there we will check if
user ID exists in case, yes, we will again use this
term operator in case yes, something will happen
there, in case no, something will happen
on this false position. When user will be locked in and he will have this user ID, that means when he will
click back on pricing page, we will redirect
him to a dashboard. When he won't be logged in, so it will be unauthorized user, he will be redirected
on a lending page. Why to implement this is because we will have pricing
page in root folder. Everyone can get to
this pricing page, and to log the users
will usually get to this pricing page
from a dashboard. So when they want to go
back from the pricing page, they will be redirected
back to their dashboard. And when users are
not logged in, they are going to this pricing
page from a lending page. So when they will
click on Back button, they will be redirected back to lending page
because maybe they will want to check out the demo again and just check
the lending page, and they will want
to still decide if they will buy our
product or not. Now, if we go into the
render of this component, what we just need to do is
set action to this form. For this managed subscription, it will be the create
customer portal. And for this subscribe, it will be create subscription. Then on the card, I
will add the B button. That means somewhere there, I will create a link. I can import it, and inside, I will put back with back
arrow that should be this. If I'm not mistaken, let's see. For this link, the HRF will be B link and some classes also, we will tert end of text
small, font medium, text, primary underline offset
four and on our underline. Let's save it and let's
go to our page and see how it looks
like, and it works. Now we go back to Dashboard and we can test the
world functionality. Let's click on subscribe and
we got redirected to Stripe. We can see the price of
our product is there. Email is there. Let's
now fill the data. Now we got redirected
to payments success, and we didn't code
this page yet. Same story for
payments cancelled. But being on page
payment success means that our payment
was successful. In our super baase, you
can see that we got a new subscription there
connected to our user. That means the payment and subscription status
update was successful, so our Stripe webbook
is working fine. Now we can go and go to
the next functionalities. For example, we
now need to tackle the successful and
cancel page in our payment folder in case the stripe payment will end
with a good or bad scenario.
10. Payment Pages: Now what we will do is
that we will create the folder in app, we will call it payment. In this folder, we will create another one and it
will be success. And then click there on the payment and create another
one and call it canceled. Inside these two folders, we will create a page dot Tsix. Same here. And now we can start in
canceled page T six, we will define this as use client as it will
be on client site, and we can start with export
default function cancelled. And inside, we will
do the return, and in return, we will
start with the dif. In this div, we will have heading one with
payment canceled. Below, we will have
a paragraph tag where we will have the description
of what just happened. Your payment has been canceled. No charges were made. You can do something like this. And below I would do a button and our button that we
imported from Chet CN, which will be this one,
inside this button, we will do a link. We will import the
link from next link. Now we will add their TF, and that will be to pricing. We will return to pricing. Now let's add some styling
for the dith that wraps this. We will do flexbox layout, flex direction column, then
items center, justify center. So we have it nicely centered horizontally and vertically. Then minimum height screen. Now if we will save it. We also want to see
what we are doing. I will go there on my page, and in the URL, you will do slash payments CansLD Now we can
already see it there. For payment canceled,
we will add font, both and text to Excel. Now we will add the space Y six. For paragraph, we will add text Excel and I think that can be it. We will click on
Return to Pricing, this should work, and it works. Now if you will go to actually, let's first take this, copy it, go to success,
paste it there, rename this to success, save it. We can go back to page. There we will do slash
payment slash Success. Now we will change this
to payment successful. And we will change
this paragraph tag to something like thank
you for your purchase. Your payment has been
processed successfully. Now we will save it and we can see how the page looks like. And maybe we can also add some div that will have width of 300 pixels will have height one will be
background green, 300. Height, actually,
let's change to something like ten pixels.
Let's see what happens. Okay, one pixel, three or two. Yeah, now it looks better. That means the payment successful page will
look like this. If I will copy this and
paste it to canceled, I will change this to red. Let's check how this will
be on a mobile phone. I will change this to iPhone 14, and we should add
their text to center. Otherwise, it looks fine. Let's go back there. Let's put their text center
to the main wrapping div. Now let's copy it also
to a success page. Now let's check it again. We can do the inspect and
we can see now it's fine.
11. Sign In, Sign Up: Next thing we will do is that
we will go into app folder, and there we'll click
on create a new folder. We will do the parenthesis
and create there off. This means that this won't
be visible in route. If we will put this
sign in and sign up, the route won't look
like off slash sign in, but just slash sign in. We will use it because
better folder structure, so everything related to off of user will be in this folder. Now let's move it
there. It won't be easy because we are not able
to move the wall files, or at least I'm not able to do it. Let's move it like this. Then I will put
there this sign up, and now we will put
sign in into sign in and sign up into sign up. Now, it should be
fine. We have there to sign in. We have
there to sign up. And the next thing where we will do is not only just making
the better structure there, but also making a styling
for our sign in and sign up, even though it's from Clark, let's now go to it. What we will do is that
we will click there on Sign Out and click
again on sign in. And we have there two pages. First one is when we are
clicking the sign in. But when user is not registered, you will click on Signup and it will change
the page for us. Let's go back to our IDE, open the signup page. Let's make sure we have it
opened also on our SAS page. And there we can start styling. Let's first start with creating parentheses
for this return. We will still use this signup, but we will also
create a dif and we'll put this signup tag
inside this div. Now for the signup,
we will keep it, but we will add more
attributes to it. First attribute that we will add will be called appearance. Inside this appearance,
we will do elements, and there we will do the
separate styling for all of the elements that are
in this sign up component. I will do an example here. I will put there footer, and for Footer, I will
add styling of hidden. Now you can see the footer of our component of
signup disappeared. And we will like this style all the elements that are
inside the signup component. Maybe before we do this,
let's start with the DIV. And in this div, we
will do heading two, and we will call this
create An account. Below, we will do
paragraph tech, and inside, we'll do
signup to get started. Now let's add some styling. So for the main div, we
will add margin from top, flex Books layout items
and Justify center, flex direction
column space Y 12. And also I think this is it. For the dith below that is wrapping this
heading and paragraph, we will put text to center. For heading, we will
do text tree Excel, font bolt, and text foreground. And for the paragraph tech, we will put margin from top, even though this could be
handled by space Y two, for example, text small, text muted, foreground
as a color, save it. Now let's check how
this looks on the page. Maybe we can do
their text large. I think that's better. And now we can get to styling
of this sign up component. Let's start there with
styling of the card. For the card, we will
put the background card. Then we will continue with
border and border border. We will add some shadow for the light mode and rounded
Excel with some bedding. Yes. Now the next element
will be header title. We can make this hidden. For header subtitle, we can make this text
muted foreground. Let me check out
this looks like. Now, next we'll
be social button, Block button, and Google. There we will set background to. Let's use white because
it's really barely visible. Yeah, I think we will
use white there, even for both dark
mode and light mode. Also, we will use, I think we will just
keep it like this. Our background white
with 0.6 opacity. Yeah, I think this is fine. And for light mode, it
will still look good. Maybe if we do foreground. But it won't look
good for light mode. I would keep the
background white. Now if we will continue, we will do the divider
text, divider text. There we will set text
muted foreground. Now, divider line. This one, we can set to background border. And on the page now,
it's barely visible, but it's there as
a nice dividing for Google App and email. Now let's continue
with Form field label. For this, we will
set text foreground. Now how to do the link
to sign in on our own. We will create link. We will click there on Import. This way, we will have it
there from Next Link library. And inside, we will put
something like actually, let's just copy it from there. But first, let's edit the Hf. So it works to sign in. Now we will have it on the page. There we will copy this. We will put it there. And we will do it like this. We will put all of this
sentence into paragraph tech, and we will leave
darlink for the sign in. That will redirect
user to sign in page. The styling of this,
we will copy from this sentence of
this paragraph tag, sign up to get started, put it there, save it. We will hide this scooter. Now we will check how
the page looks like. We will add there for
this link underline. Now, that will be it, if you will click on this link, we will get to sign
in page there. That means we can now and we are ready to style
the sign in page. Let's go there and sign in. And what will help us is to
just copy this put it there. Then we can see
what we can reuse. We can reuse this
import of link, and we can just
paste this sign in, delete these lines of code, put it there, and then save it. Now, remove this hidden footer. Go to the page, copy this. Don't have an account, sign up. Now we will put it there on
the last paragraph tech. We will take this
sign up and put it there instead
of this sign in. What is important to
mention is that we cannot have this single quote there
for the paragraph tech, otherwise, this will
fail deployment later. Let's add there this, and this is there for a
sign of this single quote. Now, if we will check the page and add this
footer as hidden, I think we have it
for the sign in, and now we can try to click on Signup and it won't
work because, of course, as we are
copy pasting code, we usually forget something. So take care when you
are copy pasting, and this should be sign up
in this href of the link. Otherwise, of course,
clicking on it would redirect us to sign
in where we currently are. Now, let's try this, sign up, sign in. Everything looks fine. And in light mode,
it looks fine. And now we can sign in
12. Subscription Check: And after we signed in, we can now see that we
are on the dashboard page where you are not
subscribe is shown to us. But if you click on subscribe, and click on Managed
subscription. We can see we have an
ongoing subscription, so we should see the product, of course, and that is something
that we will code now. We don't have any functionality
for showing our product because we will go there into
Dashboard and page TS six, we need to do that check if
the subscription is active, and in case it will be active,
we will show the product. In case not, we'll just return this. You are not subscribed. We will import Prisma
from our lip folder, DB then we will import redirect from next navigation
and that will be it. Now above the return, we will create a new
constant with user ID, and there we will use the off. It will be imported
when we click it. Now we will check if
the user ID was found, and there in case not, we will redirect
to sign in page. Then we will query the database for the
user's subscription. We will do constant
subscription, awaits Prisma subscription
dot Find Unique. The inside, we will do
where user ID is user ID, and we will select status because we are curious
if the status is active. If we will go into return, let's do the empty fragments. The check will look like that if subscription dot
status is not active, then we will return this text. In any case, it is active, it will be returning this
main dashboard content where we can for now put the similar text
and right there, subscribed to the app, and we can delete the button. For now, we will just
have it like this. Of course, then we will put there the main content
of our product. Let's go and check the page, and we can see that we are
subscribed to the app. Now let's sign out, and we will sign in with
a different account, and we can see
that we have there the information that
we are not subscribed. Now next test we can
do is that we will go into Super Base and we
will change this to active. KK, for example,
really doesn't matter. This is just a test and
we will go back to page. We will see that we are
no longer subscribed. Now let's go back to Superbse, change this back to active. And we are again subscribed. Of course, this was
generated by stripe. Now we just tested it
that it really reads the status value and it works. What we will do now is that
we will go back to our IDE, and there we can
delete these fonts, and we can prepare
a few more folders. First, will be in dashboard, and there we will create a new folder with
underscore components. That means we are
creating a private directory for the dashboard, and in these components,
we will be inserting only the components related
to our dashboard page. Then in the components
in the root folder, we will create a new folder and this will be
called Landing page. Also, remember, let's do
ending dash page because Next JS is using Kebab
case and not Cam case, for example, like lending page. And we won't be doing
the underscore there. As we will be styling
the lending page, we'll put all components into
this lending page folder. We will have there, for
example, testimonials, product demo and so on, and for this purpose, we will use this folder
to achieve a nice folder structuring in our project and whenever we will
come back to it, we'll know where we can
find each of our component. Seeing the page when
we are signed out, we can still see there the
product profile and pricing. Even though we should see only pricing
because product and profile are some functionalities
only for log in users. What we will do is
that in our IDE, we will go to Navbar because
there is the functionality, and there we have
hard coded is signed. With Clark, this is
really easy to handle. There we will just
do and put this in curly braces like this
and do use users. It will import it there
from Clark use user, then we will rename
this to assigned in. We will reuse it there. We will save it, and now this
should be handled for us. And now we implemented
the functionality. So whenever user is
locked in or locked out, we will be based on it showing some menu items
there in our Navbar.
13. Product: In the dashboard folder, I will go into the components, and there I will create the
main component that I will call thumbnail
previewer dot TSX. There, I will
define and indicate that this is a client site
component with use client. Also, I will import the necessary react hooks
and other components. I will first import their
use state and use effect. And I will also
import the input from the custom input component
we are using from Chet CN. Then I will continue
with importing the button then with the laptop, tablet and smartphone
for the icons, and also importing the use team as a hook for team management. As for the images
that we will be showing in the YouTube Mc, we'll be using URL. I will define the constant
of a placeholder image. That will be there as
a placeholder image. In case there won't be any
real image for the thumbnail, and there we should ideally put the URL of this
placeholder image. I will be using
placeholder dot SVG. With height 720 and width 1,280. Now you will need to
define an array of random video objects for the initial display that we'll
be showing on our product. I will create their
constant of random videos. And there for every video, I will define a title channel we H and thumbnail itself. Into the stump nail, I will be putting the URL of the stump nail. How
I'm doing this. I'm doing this manually
because I'm not using any functionality for the
admin to deploy thumbnails. It can be made. I also can be a good idea, but for our use, it's enough if we will
just do this manually. Because we can preset this and just leave it
there for our product, maybe updated every month. I'm using this
page, uploadf.com. There you will just
connect your Git up. You will click on Upload. You will put there
some of the image. For example, I put there the thumbnail images, I download it. Then you will click on
these three dots after it's uploaded and you will
click on Copy file URL. After you will click
on the Copy file URL, you will have it in your
clipboard and you will just paste it there into
Thumbnail URL. Then you will just
put there some age, some views. Channel and title. Like this, I will now input there some of the
videos I will be using to recreate YouTube UI
for testing the thumbnails. You will have this
in the project on my Git that will be linked in the description
of this video. So if you don't want to now
put the work into and upload all the URLs and paste them
there into the thumbnail, you can just reuse mine. But be careful. There's a chance that these URLs are no longer valid because maybe they go delete it from
my upload or so. If you want to be
sure that these thumbnail URLs will work, just use yours or at the thumbnails into
the assets somewhere there and put there
the source files. Now we'll define the interface
for the component props. Let's do their interface. Thumbnail reviewer. Where we will do channel
name saved to string. Channel name saved is
something we don't have yet, but we will define it
in profile in while because to make our user not write his channel
name all over again, we will save it for
him in our database, and every time he will want
to test the new thumbnail, we will display it. Now let's define the
main reviewer component. There as a prop, we'll
do channel name saved. That should be a string. We will start inside
the component with defining the state variables
using U State Hook. First, will be a title with set title and the default
value will be empty. We will continue with Tumbil
URL with set thumbnail URL, and default value again empty. Then with the channel name, that will definitely be again empty and then with the videos. There will be a state
for the video list, and there we will
input random videos, which is the array
that we have there. We will continue with layout. For layout, the default
value will be desktop. And let me explain. We will be using their multiple layouts. User will be able to select if you want to
display this UI for the thumbnails as a
desktop or tablet or mobile because when he will
be testing the thumbnails, we want him to be able to test it for all the screen sizes. Let's continue with use
effect to update video title, channel name or thumbnail URL. We will define use effect. And inside, we will
set videos with Title two channel name used to zero age two now. By the way, this will be the
setting for the user video. Thumbnail to URL or placeholder image in case he won't load any
thumbnail image, and then we will set
it with random videos. The dependency array will be whenever the
title will change, channel name will change or
thumbnail URL will change. Now we'll declare function to randomize the order of
the videos because we will have their button that when clicked will be
randomized disorder. So user then will be able if he can easily spot his
thumbnail or not. Let's create a randomized order. And set videos where
you do breath videos. Dot SO and we'll call
math dot random -0.5. And what this does is that this function will
randomize the order, as I mentioned, and it
will create a copy of the previous video array
using the spread operator. Then it will use a
sort method with a random comparison number that will return
minus five to 0.5. And then setting the
new randomized array back to state using set videos. Next function we will need to declare is a function to
get the appropriate grid. Based on the current layout, we'll create a function
called Get grid class. There we will switch on
layout and how switch works. In case this will be a desktop, we will return grid comes
one with a small screen, grid comes two and a
large grid comes five. Then we'll do in
case of tablet we will return also grid calls one with small screen and
above grid coals two. We will set maximum weight
to thousand hundred pixels, and we will center
this with mix auto. Then in case of mobile, we will return grid coms, maximum weight of 340 pixels and the mix auto the last
one will be default. That means default,
this switch will return Great columns one, small screen, great columns two, and large
screen, great columns four. Whatever will be passed
to this get grid class, we'll consider the
desktop tablet or mobile or devolt of course
in case it's other value, and then it will return and apply these talent
classes we defined there. We will do their return, and inside, we will
start with the Div. For this div, we will
add class names. We will do their relative
width and height to full, then G two background. And text to foreground. Inside, we will start with the input and preview
section. We'll do the div. And for this dip, we will
put a maximum weight to 1,200 pixels mix
do to center it. Inside, let's start with another div where we will
use the grid layout. On medium screen, we will
increase it to grid calls too, and we will put there some gap. Inside, we will div that will hold the inputs
and below this dith, we will create also a div, and this will hold
the Tominal preview. Let's start in the upper div. There we will start with
heading three input. Then the two inputs we will hold in the div for the inputs, we will use space Y or inside, we will do an input. For this input, the
attributes we will add will be
placeholder to title, value to title, and on change, it will set title to
the target value. Then we will create
another input. And in this input
will be a type file. Then it will accept only
images and non change, we will create a file where
we will set a target files, the first in the array. And in case this
file will be there, we will create a
constant of reader, new file reader, and we will call this
reader on load method. Where we all set thumbnail URL
to the target of the file, we just load it. And we will read as data URL. Now we will save it and also
to see this and test this, let's go to page
there on the page. We just double check
its dashboard page. We can add below the subscribed to app thumbnail per viewer. Import it, have it there. Now we need to input also
the channel name saved, where I can put test
for now, save it. Now it will be
displayed on our page. And let's get a bit back to this input that maybe I need
to explain a bit better. The type pile will create
the input for us where we will be able to select
the file from our PC. The except image will make on images being available
to pick for us. This change will run whenever
we will pick a new file. And what we will do
there is that we will get the first file
that was picked. Then if it's true, so if the file exists, we will create a special tool that can read the file reader, and when the file
is done being read, we will save the image
data as a URL string. Then we will start
reading the file as URL. We can now go to our page. There you can see we
can put some title, and there if clicked,
I can pick an image. Now the image is
not yet preview, I will leave it there and we can move to setting the image previewer there after this
input and also after this div, let me show you
where this starts. We will create an input. The attributes we will add
there will be placeholder, that will be channel name saved, which is the probe
we are sending to this component or
just channel name. Then the value will be the channel name or a
channel name saved. And on change we will set
channel name to target value. Now we will head into
this second div, and we will do the
image preview. There we will start
with heading three, and we'll put the
thumbnail preview. Let's add the sum classes. Let's do textarge, font medium, leading six with
margin bottom four, and that can be it for now. We'll continue with the diff. For this div, we will put
the classes of aspect width 16 and aspect height nine. That means we want to maintain the aspect ratio of 16 to nine. Then we will use rounded large to increase
the border radius. We will set overflow hidden, so nothing will get
out of this dith and also we will set w
to, let's say, 60%. Then inside this dip, we will create an image. Attributes we set there
will be the source for thumbnail URL or
placeholder image in case it will be empty. Then note thumbnail preview, and then class names
with object to cover w and height the full. Now you will save
it, you can see that there is the image I put
there into the file. And that is there. Now we can style it further. I think I will start with
taking this class name, space y four and
putting it there. Also, between these two inputs, the input one and input two, we don't have any space because this should be actually
put next to the inputs. And maybe we can even
delete this wall Div. I mean this one.
That means we can format it like
this, put it there. This one like this, save it, and now it will look better. We have this nicely
aligned with inputs and thumbnail preview where
there are the inputs. There is the preview of
the thumbnail we want to show there in our product
that we will define below. And for now, it will be
enough if we will put the border to bottom and border white with
points to opacity. Maybe also we can add
some padding to bottom, 12, Now, if you will check
where this di ends and below, we will put some
content and save it. We can see how it's
being divided. We can name this
or command this as an input input and
preview section there we can take this command, and below, we can start
with the product section. We will create a div
there, and first, we'll do randomize order
button with layout slider, where we will select the layout
that we will want to see our thumbnail on and also we
will have randomized button, where we can shuffle all the video cards that will
be next to our thumbnail. Randomized order and
layout selection. For this randomized order
and layout selection, we will set the classes
of margin to bottom six, Flexbox layout with
items to center space X, so horizontal spacing, we will make there between
arronments to four. Then we will set a
maximum weight to 1,200 pixels and a mix
order to center it. We will have the button first. And for this button on a clique, we will call the
randomize order, and we will name it
randomize order, which is kind of obvious. Now we will save it. Let's
check if the button was edited and I can
see it on our UI. Then we will
continue with a div. And for this div,
we will add classes of flexbox layout
again, items to center, space X two, round it to we can do full as this
will be some slider. Let's add some padding to it. We can shadow, and I think
we can save it as is inside, we will add a button, and this button will have
the laptop icon. For this laptop icon, we can just set something
like height 24 with 24. Then let's add some
classes there. For the button, we will be setting actually first
some different attributes. And that will be a variant. We will set with the
Turner operator. Let's check if the layout
is set to desktop. In case yes, we will
use default styling, in case no, we will
use Ghost variant. Then we will continue to
size where we will set icon. Then we will set
OnClick function. That will be setting the layout. So in case user will click on this button for the desktop, he will be setting
layout to desktop. And then we will label
to desktop layout. Now below, we can continue
with another button. There we will use
the tablet icon again with some classes, high 24 with 24, and
we will cose it. For the button, we will
again add some attributes. I will do again the variant that will check with
the turner operator the value of the layout. And in case it will be tablet the true position will be default and false
position will be ghost. So in case this is not true, it will set the variant
of this button to ghost. Size of this button
will be icon, then on click will be setting the out state variable to tablet and label will
be tablet layout. Now we will move to the
last button, and again, there will be smartphone icon with classes high
24 and with 24, and the attributes will
be again, a variant, where we will check the layout
in case it will be mobile, we will execute the
default and in case not, we will set a style of a ghost. For size, we will
again set icon. For click, we will
called the set layout, where we will set the
state variable on mobile. Then the label will
be mobile layout. Now, if we will go to our page, I can try setting a
different layout. And it's working,
you can also see how it's switching the
variants of the buttons. So the selected one
is a default variant, the not selected are
the ghost variant. Of course, it will
be switching also the styling of the UI for our
Mc of the YouTube reviews. Let's move below this section. We will take the command there. We will put it above the div we will create
and we will put there video cards for
thumbnail reviewing. Below this command,
we can create a div. And in this div, we will do class name where
we will put back quote and we'll put
the grade class name, and then next to this
grade class name, we will put $1 sign and the
values from Get grade class. There, based on the layout
we will select will be desktop with these
columns two or five, tablet with maximum weight and mobile with also
different maximum weight. Now we will also
s there a gap to six and also based
on the layout. In case if the layout
value is mobile, we will set the width to full. In case this will be false, we won't set anything. Now we will map over
our wideos array. Widow will be the name
of the current item in the array and index
its position. There we will now open
this and we will put there a div into this
div we will add a key. This key will be an index. Then we can save this already. We will continue with
adding their class names, and we will use their back
quotes because there will be a variable check or
turn operator on the layout as we will be checking if it's a
mobile layout or not. Let's do curly braces and put
their back quotes inside, and we will start with the
normal tail end classes. Let me start with the
first one and that will be overflow hidden to not get
any content out of this div. Then some shadow. Then round it large. Also, we will put there now
the check for the layout. So we'll do turn
in operator there, and in case it's mobile, we will also return for
this maximum weight of 340 pixels and mix to center it. Otherwise, if it's not
mobile, just return nothing. Now we can go inside this div, create there another one. For this dip, we will add a relative class and
some padding to bottom. I will put there something
like let's say we will do 60. Then inside, we can
start with image tag. And we will add the
attributes for the source, which will be a video thumbnail. In case it's not there, we will use the
placeholder image. We will continue with OT, which will be video thumbnail. Then we will continue
with glasses. There we will put absolute
position inside zero, width and height to full and object to cover to show
the best of the image. Then we have closing of the
div and below this div, we will create another div. Now you can already
see we are displaying the video thumbinails
on our page. So everything we loaded
there is being displayed. But of course, it's
still not in the shape we would like it to
because currently, the image is taking the full width of
the wall video card. This is not how it works. Instead of, let's say, 25% of what we can see
on the one video card, which is the one square, we need to also display
there the title views and when it was uploaded. Just the standard video card that is on YouTube, for example. Let's go back to this day we just created because
we will do it there. For this new div, we will add a bedding and also we
will add another div. Inside this one, we will
put the class names with flexbox layout items
start and spacex three. We will do a first
paragraph tech that will hold the Widow title, then a next paragraph
tech that will hold with the channel in case it's empty, I will put the channel name saved because that will be
the channel name of our user. So he will have it pre filled. And next paragraph
tag that will hold the video views views, and now video age
and also we need to do period there between
the views and video he and now it's
looking a bit better, but of course, still
some styling left. So let's now do it. And we also forgot the avatar. So we need to d it there.
Let's add there a div. And inside this disk,
we will put image, and we will again add
the some attributes, which will be video
thumbnail for now. We will use video
thumbnail as an avatar, so we don't need to again load now the separate avatars
for every channel. There would be much
work on top of this because it's just
about uploading the images and putting it there. I believe this is
easy to do then, but it's just a lot of
repetitive work to do, but everybody will
probably do it themselves. It's just about loading there instead of the thumbnail, URL, also Avatar URL, but
I don't want to again reload to the upload thing
like eight images for Avatar. So I will just
leave it there and I will reuse the
video thumbnail. I believe on the testing
of the thumbnail, it won't have any effect. So for Avatar, we will use video Tumnail in
case it's empty. We will use a placeholder image, or it will be channel Avatar, and classes width to nine, height to nine and
round it full. Now what we will also add for this avatar will be flex shrink, zero, and also what we will add there for this flexbox layout will
be flex direction column. Moving there to
these paragraphs, we will create a div for them. We will set to this dein
with zero and flex one. Maybe now we can delete
the flex direction column. Now we will see the page. It's already looking
good on the tablet. We need to fix this
for the desktop. Let's continue with the styling. Maybe I can also make it a bit bigger so we
can see it better. Like this, and we can
continue with the styling. For the paragraph, I will
put there first classes. I will start with text small,
font, medium, truncate, font heading, and I will use
a text color of this code, which I had in my design file. Then for the next paragraph, I will again use Tex small. And now the color to have it exactly as on the UI of the thumbnails we
want to recreate, I will put there the
code of a really, really light gray color. Now I can just copy paste this also to the next paragraph. Let's see how it looks now. Now we are pretty
close, I believe. I will What is the issue there, though, is the weight of the
video cards for this test. Let me add some thumbnail. I will put there, for
example, this one, first thing we
will do is that we will remove a
maximum weight from there to have it
like this exactly. And that means I
think in the end, we can also remove this div. Let's take the closing
tag of the div there and remove it there so we don't need to keep the
empty additional div. Now, if you go in the page, it looks like more UI
with the video cards, but I guess we will still
need to quickly check the proper width and height
and set it as it should be. The ratio we would like
there is nine to five. How we can achieve this is that we will add
padding to bottom. That means let's go to code. Let's go to the thumbnail, which is there this one. Now we are using
petting to bottom 60, but I will put there
bedding bottom to 55%. I will save it, and now we have the video ratio we will use for our tumnails now it's
finally looking like we are on some page and we are listening
through the tumnails. Let's now, as we already
filled in the data with the tumnail test the
functionality itself. So I will randomize the order, which is working
properly, so it's fine. Now I will write
the tablet version, randomize it also
there, so it's working. I will write the mobile version. And on mobile
version, we can see that we have a smaller d. So we need to fix
this da layout, mobile, maximum width, and Modo, and width to full. Save it, and it
will be all right.
14. Landing Page - Animation Container: Container. This will be a component where we will put motion div and
animation set, and we will be then just
calling this and we'll be wrapping our content to it to have our landing
page also animated. We definitely don't want to rewrite all the motion dive into all the components we'll
use because there will be a lot of additional
lines of code. We can just do it
there, put it into global component,
and then reuse it. Let's actually start with writing this
animation container, so we can then reuse it
in our hero section. Use client, so it's
rendered on client site. Then I will import the
motion from frame or motion. We don't have this library yet, so let's open the terminal. Let's run NPM I framer motion, install it, and now
it will be fine. We will define the interface for animation container props. We will put the
children will be react dot react note Also
with a small N, then we will do delay, that will be a number, reverse, that will be a bulling, then class name will
be a string, animate, that will be NA, then
initial also NA exit, and mode, there
will be a string. Then we need transition
and onclick. So transition and
onclick function. We will define this as white. Now we can continue with grading constant for
animation container, and we will start
defining the props. First will be children,
then class name. Reverse I animate, initial exit transition,
and that's it. Also on click. Then these are animation
container props. And there we will be
returning the motion div. And the attributes for
the motion div will be a class name with class name initial with initial
and in case it's empty, we will put the opacity
to zero and white to operator of rivers depending
if the reverse is true, we will put there -20. In case it's false, we
will put there just 20. Then animate, again, we
will set the animate. In case it's zero or doesn't
exist at all, I mean, we will set opacity
to one and Y to zero. This means that when
the value is not there, so we are using this or, we
will execute this value. So this animate will
have this value, but in case we have
some value for animate or initial they
find there in the props, it will use that value. Let's continue to
exit that we will set this exit, then viewport, where we will set one fast
because we want the animation to reappear when we will be entering out and
in the viewport, then we will set the transition we will check for the value
in case it's not there. We will set the duration. So some base values for
our transition animation, I will set duration to 0.2, then delay to delay is, I will set to is in out for some smooth
acceleration type, I will set to spring. That means it's
using some physics based spring animation. We will set also stiffness
to 260 and damping 220. Also, for on click of this div, we will set the onclick
prop then inside this div, we will render the children, and that will be it. We will then just export
default animation container. And that's it. We have our animation
component that we'll be using to wrap our content
to have it animated. Let's go into hero component, and there we can
finally start coding. I will start with imports, and I will import the
link from next link. Then I will import the
animation container, and that will be for now. We can move to creating
export function hero and there we will be
declaring everything into this return. Let's do this. And there we'll start with the relative class,
then flexbox layout, flex direction, column
items to center, and let's do some spacing. I will use space Y 20, and on medium screen, we'll use space Y 40
to have some even spacing between the
elements on this page. Inside this div, we will start with the
animation container. And the only thing I will say there will be
the flexbox layout, flex direction, column
items to center, justify center,
and width to full. Then inside, I
will create a div. For this div, I will add a margin from top
on medium screen, I will increase it a bit
and appendix to four. Now we can finally start
adding the content itself. So again, animation
container to have everything animated and there
put the first property, that will be the delay which
we will set there 4.2. And inside, we'll
put heading one. That will be thumbnail reviewer. Now we will have it on
our page very soon. Classes for this will
be text three Excel, small screen text for Excel, medium screen text, six Excel, and fond boat and margin bottom. Now to have every component
we will do on our page. We, of course, need to
add it to the page. So an app, and this page, we will start in the components. So I will add their
hero section. And like this, I will be adding there all the other
components as well. You can see that the
terminal perview heading now was displayed
on the landing page. Behind, we have the grid layout. It's starting to look
good and we have there only just two words. So hopefully this will go
smooth. Now let's continue. What we will do
next is that below this animation container,
we will redo it. We'll again call our component
Animation container. We'll put there a higher delay. Let's do 0.3. And inside, we will do paragraph tech. Inside this paragraph tech, we will write review your thumbnails in a
realistic environment. Now we will do the
spacing, Spen tech, and three easy steps because we need to do some nice promo for our product so people
will actually buy it. We will start doing the styling. I will put the text
Large text seven Excel. Text to Excel on small screen, text Excel, medium, text, to Excel, font to bolt, margin to bottom, maximum
width Excel, and a mix auto. Maybe we don't need
font bolt actually, and maybe we also
do text center. Let's put a Spen tech on the next line because we
will add the gradient text. And what is this gradient text? It's actually some
custom gradient text we will now do in
Globals dot CSS. So let's go into this
file Globals dot CSS. There somewhere we can
do it on the bottom. We will go to the CSS
classes for gradient text, but also for the button.
It will be easy. We'll just do the gradient
text and put there at apply background gradient to
right from and color number. Via again, color number. Two, again, a different
color number. Now, I believe we have it, so we can just copy this
and paste it below, call this gradient button. And actually, what we
will do is that for text, we should also add text transparent and
background clip text. Now it will be fine
and it will work. We can go back to
our hero section. There you can now see how
it looks like on our page. Opacity to 70. And maybe that
looks even better. Now as we did also
the gradient button, that means we'll do
the buttons itself. Of course, let's continue
below this animation, and we will add there again animation container with D 2.4. And inside, we will do
a div for this dip, we will add a
flexbox layout with flex direction columO
small screen and above, we will make it
flex direction row, it's next to each other, justify center, then space Y four to have there some spacing between on smaller screen, we can reset this
space Y to zero. Again, on smaller screen, we will just need to
add some space X to four because the buttons
get the different position. Inside, we can start
with a button. Let's also import it. So if you don't have
the button yet, just run this command N PX
ChetcN at latest at button. And by this, you will
add any component from the ChetsiN library. You can also make this
command chest at card. You will add card
to your components, and then you can
reuse it like I'm using this button or not now, but very soon, yes. We need a some attributes, starting with variant
where we will put default. Then with sizing, that will be large setting as child
and also class names. For class names,
I will put there the gradient button
transition transform because I will be on Her
increasing the scale to 105. Then I will set also text
foreground and font both. Now let's add a link with HRF to most probably something like dashboard and get started. Now we can see the button. And below, we can continue
with another one. Let's prepare the attributes. We will use variant outline
now, then size again, large as child and also class names that
will be with two full and on small
screen with two auto. Now we need to add some content, so link with HRF two pricing, and it will say view pricing. Now we have both
buttons on the page. We will move to the next
component that will be right below our introduction
on the landing page, and it will be steps
component where we will demo user how easy is to use our
product in three steps.
15. Landing Page - Steps Component: I will do export function
steps with some return. I will go to page, put it there, Import it, and we can happily
continue with coding. In the step section, we will first do some imports, and we will start with importing the image from next image. Now I want to put
there some pictures, I will put assets folder
into my app And from there, I will import the thumbnails, so I will import thumbnail one from app assets one dot BNG, and I want to also do
it for thumbnail two. And the same thing
for thumbnail, three, and that's it. Then I can import icons. I will be using pencil from
lucid react, layout, and I. Then I will continue with importing the
animation container, and I can go right to steps
component into the return, and I can start there with the animation container
as a main wrapper, put a class name of mix Auto, maximum weight to seven Excel. Margin to top and relative. Then I would also like to
close the tech, of course. And inside, we can start rendering something.
I will put there a div. And in this div, I will
start with the top border. We'll be using their
borders around our steps, and the first one
will be in this div. So actually, it won't
be even opened div, and we can start with
absolute position, top zero, left zero, right zero,
height two pixels. Background gradient to
right from transparent via foreground with 0.5
opacity to transparent. Now you still cannot
see it on our page, only we will put there
something like this, and now you will check the page. You will see it there
a little bit above it. But of course, as we
will add the steps, it will be nicely visible. We will do their left
vertical border. Again, it will be closed
on the first line. And for the classes, we will at their absolute
position, left to 33%. Then I will continue
with setting top to 10%, bottom to 10%. Width to one pixel, background gradient to
bottom from transparent, a foreground 50 and
to transparent. Now one more diff and we are going straight to the content. So again, like this and put
the classes of absolute. This one will be on right, 33%, top, also, 10% to bottom. With the same width.
Now seeing it maybe I could just
copy paste it, the ground gradient to bottom from the transparent
a foreground with 0.5 opacity to transparent. Let's add the content now and we will see
how this looks like. First, for this day I
will add a grid layout. And in this grid layout
will be the three steps. So on medium screen, it will
take grid columns three. Inside, we can call the
animation container. There we will put some
delay 0.2 for class name, I will input group. And inside, we will do
a div and there we will add classes of relative,
bedding, eight, transition all duration
to 300, BG background, with 0.3 opacity to change a bit on how we will
make it 0.5 opacity, then a backdrop blur small, some shadow, and on how we will increase
the shadow to Excel. Now, let's just first add some content to style
the other things. What we should put
inside is first the div that will
hold the step one, which will be
basically the icon. And next to the icon will
be a text with step one. Then below this div
will be a paragraph. So upload your
thumbnail and details. And then below, we will
also put the image. So I will create the div with image the image will have
a source of the thumbnail, one out of Tumbernil one also, and then fill and the
class name of object to cover transitional duration 500, group hover with scale one oh five to increase the size
whenever we will hover over. Now we finally have
it on our page, so we can style it better. And you can see the layout,
how it will look like. So there will be the first step, there will be a second one, and there will be the third one. Of course, we will style it, so it will look even better. Let's now continue. Let's do the comment that
we'll call steps. There we can start
with the styling. So for this dish that holds this step
one with the pencil, I will put their margin bottom. Inline flex. Then I will continue
with items to center, some gap, and some padding. Then I will make it
rounded to Excel with border and border
primary with 0.1 opacity. Now to the dipth below
that is holding icon, I will put some bedding, I will put some background with primary color and 0.1
opacity and rounded Excel. Now it's still not visible
because the image covers it. Let's put the styling for
the image, I would say. For the image, we will
set relative height to 52 with the full
overflow to hidden. Round it to Excel, border and border white
with 0.5 opacity. Nice. Now the step is finally visible, so we can continue
with the styling. Let's get back to this icon. But I think we actually
have everything there. To icon itself, we
will put height and width 25 with text primary. To the step, we will add the
classes of text to Excel, font medium, text primary
and tracking wider. And now only the paragraph text left there we will
put text small, text, muted, foreground,
and margin bottom eight. Now we also want to add
step two and step three. But do not repeat our code. We will just grade the
constant with steps. And inside, I will put the
information about every step. First will be the icon,
that will be a pencil, then a step, that
will be step one, then a description that I
will input there later, image that will
be thumbnail one, then image t. That will be just thumbnail or I don't
even need to put it there. I can just then do
the image into old. Then D, I will make it 0.2. Actually, I don't need
to even put it there. I can just leave it
0.2 for all the steps. Now, I will copy paste
this two more times. I will make it step
two and three. This will be layout.
This will be I. This will be thumbnail two, and this will be
thumbnail three. Now our component is named
steps, so steps array. Then I will go there above
this animation container, I will create the
steps array dot map. Name of the item in
the iteration will be step and index will
be the position. There I will now put this code with the animation container. Now, I will put
there the step step. The I will put step
dot description. There, I will put
Step dot image, and I will put there also key, which will be index only thing I will do
is that I will remove this animation container I
will leave just this div. I will move the animation
container there. I will take these
classes for the grid, put it there, remove this div. In this diff, I will put another animation
container closing tag. Now we moved it like this. Let's save it and see
what is on our page. And we have there
the three steps. What we need to do is
to increase the width. That means we will go
there and we can do background white to see how
this is currently going. We can remove this
maximum width. With mixoto. And what we can do is
that we will remove this maximum weight on
AmexooF medium screen, we'll put x like 48. Now we can check how
this looks like. And when testing this
one additional thing, we need to move this
group to this div. Now it should be fine. So
let's test the steps section. Let's test the responsiveness. And that means we can
move to another section. Next section will
be demo section, and this section is actually, I think, easiest one.
16. Landing Page - Demo Component: Let's go there to
the demo component, create the export function demo. Do a return, put it on our page. Now we can continue there
this as a client component, and there we will import
image from next image. We will import app from the assets one PNG
for my assets. Then I will import some useful
things from frame motion. It will be motion, it
will be use scroll, it will be use transform from frame motion
and then also import Rf from react because
we'll be using these refs as we will be moving this image that is
basically image of our app. So there below the imports inside the function of our demo, we'll create a const
of app image rev, where we will call the use Rev hook and set the
default value as null. Then we'll create a constant of scroll Y progress and the scroll from frame or motion where we will
set the target. So this should go to our
app image rev and offset where we will set from start to end and from end to start. Now we will create
two variables. First one will be rotate X, where we will transform
the scroll progress, zero to one into the rotation. Transform Y progress, zero to one transform
to 14 minus ten. Below you'll create
opacity variable where we again transform the progress zero
to one, 20 to two. What it means. For the rotate, when scroll progress is zero, it will be 14 degrees
and when it's one, it will be minus ten degrees. For the opacity, the same thing. When it's zero, it's
actually still zero. And when the scroll
progress is one, the opacity is two, so
it's fully visible. Actually, probably
one is enough there. Let's continue
inside the return, and in a while we will see
how this animation works. I will do the d for this day, we will set text foreground
and we will set BY 20, and on smaller screen, we can increase it a bit more. Also, let's say there's
a maximum width to 1,400 pixels and a mixed auto. Inside, we will do
heading two with test your thumbnails without limits. And there we'll put the margin
from top text to center. Text five Excel. Now on smaller screen, text six Excel, font both, maybe let's say some opacity. And below the heading two, we can add a paragraph tech. Inside we'll do review, review your thumbnails on
desktop, tablet or mobile, UIs For the classes, we'll put text
Excel, text center, margin top to five, and text for ground with 0.5. I mean 0.8 opacity. I think the opacity there
we can change to 0.9 on the heading to leave like
this, that's better. Now below this paragraph tag, we will continue with the motion diff because we'll be adding there
something that I don't want to now add
to the container, so we can maybe
later refactor it. For now, I will just use
one motion if that's fine. For the ref, I will
set the app image ref. For the style, I will
set the opacity, that I will set to my
variable opacity, rotate X, that I will set to my
variable, rotate X, and also transform perspective that I will set to 700 pixels. Let's also add a
class name there, margin from top, rounded
Excel, overflow hidden. Shadow to Excel, shadow purple. Let's add some nice
color to the shadow. Then border and border
foreground with 0.1 opacity. Now there, the final thing, we will add the image to the image we are
the source of app, which is the image we imported. Old will be epidemo,
for example, class name will be width
to full and height to do. Now let's save it, and we will have the image even
with the animation. So let's scroll down,
and there is it. And there you can
see how it's being barely visible and changes too. Actually, we should go there
and change the opacity two. Save it. Yeah, that's better. So I can now refresh
the page. Scroll down. There it starts and it gets
like this on our page. You can see how
it's moving even, and you can even see
the shadow around it. Let's now go to light mode. Yeah, it works, of
course, everything. The design is working
also with the light mode. But of course, dark
mode is much better, at least for this
design, definitely. But if somebody wants to use
just a light mode, he can. And that will be it
for the demo section.
17. Landing Page - FAQ Component: We can move to another one, and it will be frequently
asked questions. Let's open Explorer and
there in Landing Page, there we will do
Export function, FAQ, return, can do just
empty fragments there. Go to page, put it
below the demo. Import it and we are set. What we need to do
there as client one, and we will import animate
presents from frame or motion. Then we will also import state. And we will also import the animation container that we'll be using as previously. Now we will create
a array with FAQs. And for every FAQ, we will do a
question and answer. I will do the three of these. So I think three questions, three answers is enough for now, and let's put there
some questions. So the first question would be something about our product. What is TumbnailPviewer? Then how does the
preview system work? And the last one maybe, is there a plan available? In the component, we will
first grade state variable. So selected question with set selected question
to set it and use state number or null and default value of our
state variable will be null. Now we can go right
into the return. We'll wrap this in div, and we can start with
the first class. Let's make this maximum
width of 1,200 pixels. Let's make this x
auto to center it, BI 32, to have some
vertical spacing around and peaks to have
some horizontal spacing. Now if we will continue, we will create the
animation container. There we will include
some delay. Let's do 0.1. And inside, we can do the
heading two with FAQ. For this heading, we
will put text three Excel on small screen text
four Excel, on medium screen, text six Excel on font
bolt, text center, tracking tight and
now we have it there. Maybe we can put there
also some opacity to 90. Below, you will continue with
another div for this div. We will set a grid layout. We can set some
gap. We will have the frequently asked questions. On medium screen, we will make this grid cat and some
margin from bottom. Inside this dip, we will map over the array
we created there. That means we will
do FAQs dot map. We will name the current item
in the array iteration FAQ, and index will be the position. Then inside, we will create
animation container. For this animation container, we need to set the properties, and that will be key as index. Delay 20.2, and for every FAQ that
we will be mapping over, we will increase this by
index multiplied by 0.1. Then for the class name, we will have their
turning operator because we'll be checking
the selected questions, and in case the selected
question will be currently selected or the question will
be currently selected, it will have a
different color than the unselected questions to
have this differentiated. So let's actually do
there the back quotes. And inside, we can start
with Bereni to six, Berny to five, text to left, rounded to Excel, transition all duration
500 to use the animations, cursor pointer,
backdrop, Blur, medium. Now let's continue on another line that we
do the dollar sign, and insight, we will check
for the selected question. Or more likely if the
selected question is the current index, which means that is the
current item in the iteration. In case, yes, we will
execute disposition in case, no, we will execute
this position. In case it will be a
selected question, we will set the background
to primary with 0.5 opacity, border primary with 0.2 opacity. And actually, this
is not 0.5 opacity. This is 0.05 opacity. And some shadow with some shadow primary 0.0 0.05 opacity. Now we can move to another line. Let's actually do it like this. And on another line in case this is false, so
it's not selected, we'll just set background to 0.2 opacity on our
background, 0.05 opacity, border white, 05 opacity and on our border white 0.1 basidi. Also, after we can
add the border class, we should at the
border class, save it. And now we cannot
see anything because we still need to add
the question itself. Let's do the H three. Let's display there
the question. So we have it at
least on our screen, but we are not done yet
with the attributes. We also need to put
there transition, and we will set to
transition the duration, which is 0.3, type of the animation which
is spring for us, then stiffness and damping. Also, let's set there
on click function in case user will click
on this question, we will set the state variable, so set selected question. Send the index, correct number
of the sected question. Let's say we select
the third question, so it will be set to the state variable and that
question will get selected. We will test it very soon. Let's just do some additional styling for the heading tree, which is just text
large with font light and tracking white. And now
let's select the question. So I selected the
first one. You can see how everything now works together with a really light
border shadow and so on, and how I can select
the different questions and it stays selected. What it will do is that we will sag the question and then it
will show the answer below. Below this mapping, we will continue with a new
div, and into this div, we will put class names of
relative height to 140 pixels, then flexbox layout items and justify center to have it centered vertically
and horizontally. Round that Excel, border
with border white 0.05 opt, background, we will set to 0.2 opacit and backdrop
blur to medium. Inside this div, we will
throw the animate present. And for the animate presents, we will set mode to wait. What is animate present
from the frame motion? This is a special component
that will help us make a smooth animation when
things will disappear and, of course, also
appear from our page. When we will click
different questions, animated presence
will make sure that the old answer fades out
nicely before going away, and the new answer
fades in smoothly. Now we can animate presence continue with checking
the selected question. In case it's not null, we will render this
animation container. Where we will need to
set the attributes, key as selected. Question initial as opaciD
to zero with Y to ten. We would also like their animate with opaciD to one and Y to zero and exit with opacD to
zero and Y two minus ten. Then we will set a transition where we will set
the duration to 0.4. And the class name where
we'll just at some pedding. Inside, we can start with adding a paragraph tag where
we'll put the FAQs, select the question dot answer. And we will display the answer
to the question like this. Then let's add some styling. Let's put this actually
on another line. And for the styling, we will put there
text base, font, light, tracking, white, and text foreground
with 0.9 opacity. We can test it and we
can see the animation. And in case this is unselected, there will be nothing, but we will fix this
below this mapping. We will do conditional
rendering, set the question
in case it's null, we will do animation
container inside, we will display select
a question above. For there we can
reuse the styling we have on the FAQ above and we can also put there some animation or
just leave it as is. Let's now check the page.
Now we will fix the wit. Let's go there and
we will do there instead of this 1,400 pixels and we also
set it width to full. So now it will take
the full weight, but also it won't take more
than 1,400 pixels weight. Let's see how it looks like. And now you can see
that it's not changing the weight as we are
changing the questions. Also, you can see the
animations, boom, boom, boom. And one more thing we will do
is that we will do our FAQ, put margin bottom to 12. That will be for the frequently
asked questions sections, and now we can move
to the next one. And that will be the pricing.
18. Landing Page - Pricing Component: Let's go there to
the pricing and to make there some
difference between the other pricing component, let's name this pricing lending. So let's make export
function pricing lending. Now we will edit. First, we need to
do a return there. We will it on the page. Not pricing, actually. Pricing lending. Now, there what we need to do are
first sum imports. So I will do Import
Link from next Link. I will also import the
animation container and I will also import check from Lucid react because we'll
be using it as icon. There we can start
with a section. And we can put
their class name of maximum weight, seven Excel. I mix Auto, PY, 20, four, Px, four, and relative. Inside, we will do
two empty diffs, and we'll put some
classes for them. For the first one, I will put absolute position, top zero, left zero, and right
zero to stretch it from line from side to side. Then I will put their
height to two pixels. Background gradient to
right from transparent, via foreground 50, 0.5
opacity to transparent. Now below, I will basically
do similar things, but I will put it to
bottom left zero, right, zero, height. Also, we can use two pixels and background gradient
from transparent via foreground with 0.5
opacity to transparent. Now we scrolled section, we can already see the dot, but it's actually these lines, but we will see after we add some content as it
will get expanded. So now let's start with
animation container. For the animation container, we will first set
some delay with 0.0 and let me do it like this. And we will start and we will start with some
class names there. I will put there flexbox
layout, flex direction column, then also items to center, maximum width l, and Amora, width margin to bottom 16. Now let's start adding content into this animation container. Inside, we will start
with heading two, and this heading
two will be named pricing or we'll be
displaying pricing, the name of this section. And for this heading two, we will add up bedding to three background primary
with 0.1 opacity, rounded Excel, and
also text to Excel, font, medium, text, primary
and tracking wider. Now it's on our page. We can see how it looks like. And actually, I think background primary rounded Excel, we will get rid of this. Let's leave it like this and
maybe more likely find there some icon door sign maybe, then put it there. Dollar sign, see
how it looks like. So what we will do actually
is that we will create a div. For this div, we will
add a bedding 2.5, background primary with 0.1
opacity and rounded Excel. We will put the
dollar sign inside, and we will also create
there another div. Put there the things.
And for this day, we will do flexbox layout, flex row, so the pricing, we do dollar sign are
next to each other, and also we'd items to center. Let's now see how
it will look like, and maybe we can decrease the bedding there
for the dollar sign. We can do there some gap between and my las do 0.5 0.05 opacity. And that's probably it. I think we can
leave it like this. That means we can continue. And what we can also do there actually is to add
some text below. One plan rules them all, maybe something like this. Text to center, text to arch,
text muted, foreground. Let's see how this
will look like. Yeah, of course, we
need to put it below. So like this, Yeah, that's better maybe 0.8 opacity. And maybe I would also switch the dollar sign with the pricing below this
animation container. We will start with another one. We will set there a delay 2.2, and also class name, flexbox layout justify
center and width to full. Inside, we can start with
a di and for this div, we will set width to full. On medium screen, we will
set width to 500 pixels. Then we will set
the relative class with bedding to
eight transition to all duration to 300 and
background with 0.3 opacity, with how background
to 0.5 opacity. Now we will continue there, and we will say there
a backdrop blur to small then some shadow
on how we can increase the shadow and round
it to Excel to increase the border radius and add some border itself also. Now we will add some
content, finally, and we will then again, refine the styling a bit. Let's create the div. Inside this div, we will put a paragraph tech
used for one year. Something like this, maybe
we can then update it later. Then below, we
will create a div. In this div, we will create two Spen tags will be for
the price, let's say, $19. And here, Classes there will be flex
items baseline and Gap 22. Now for the span, the styling, we will add will
be text for Excel, font semibot and the
text muted for ground. Let's see how this
looks currently. Below this div, we can
continue with another div. We will create an
array, unlimited, upload, save your
channel information. Then we will map over it. We will name the item feature, and we will check the
position with index, then inside, we
will create a div. In this div, the key will be
index and the class names, we will use flexbox
layout items to center gap three, text,
muted foreground. Inside this div, we will put another div and this div
will hold the check icon. For the check icon, we
will just set height to four with 24 and also
text to primary. Blow, we will create a spenteg that will show
the feature we have there. For the div that is
holding the check icon, we will add rounded
full background primary with 0.1 opacity. Flexbox layout items to center, justify center to center it. And now we can check
how it looks like. I would also increase
the pedding. Let's put their padding two and let's also put
there space Y two. Let's say the peding one. We will create the link. We will at HF to sign up and the class name with
the full inline flex. Items to center justify
center rounded XL, horizontal padding to four
and vertical to three and transition all
with duration 500. Of course, now we
also need to put there some names so get started, and there on another line, let's finish the styling
with background primary. Then on H background primary
20 and text primary, also with border
and border primary with a 0.2 opacity and on H border primary
with 0.3 opacity. Now we have it, so we can
see it on our page there, and now we need to update
the styling a bit as we need some spacings there because currently it's a bit everything
on top of each other. Let's delete this div and let's add there space y six. So when we are hovering over it, it gets lighter, and
then the button also. For the button, when
a user clicks it, he will get redirected
to a signup page. When he will sign up, then he will be able to
buy the product. I think that's it for the
pricing page, no more things. We will now add there, and we can continue
to another section, which will be called to action.
19. Landing Page - Call to Action, Footer, Updates: Let's go back to VS code, open the Explorer, go
to the call to action. Do export function,
call to action, do return there, put it on
our page. Call to action. Now we have it and
we can continue. What we need to do there
is to first use client and also make import of the
image there from next image. Next thing would be also
import the framer motion. Currently just for testing, I will put there
import thumbnail one from the app assets and one PNG. And I will do it more times. I will use it like, I don't know, eight times. Because I need to make a full circle out of
these thumbnails. So just now for testing
and as a placeholder, I will put there eight imports like this with the same image, and later we will change
it for actual thumbnails. So I will put there
just eight imports of eight different images, and it will be all
displayed in this call to action section because it will be basically
a rotating circle. And every time on
the screen, I think, like three or four images
will be visible because the other images will be in the second half that will
be hidden below because, of course, in this section, only the top of the
ring will be visible. We can go directly
to call to action, and there we can
start with a di. For this div, we will put
a relative class with full PI 240 and overflow hidden. We will add the
great background. So let's do the div that
won't hold anything. Just two class names, we will put the absolute
position in set zero, and now we will also put there something we
already have on our page. So let's
take it from there. And basically, we want to
copy this put it there, set the opacity to 25. That should be fine then. Now we can see it on
our page already. And below, we will also do, again, empty Di where we
will put just a class name, and it will be absolute inset
zero background gradient to bottom from transparent via black with 0.5 opacity
to transparent. With this, we'll
make the darker line in our section like this. Now below, we will start
adding the content. So I will put there a div. For this diff, I will
set a relative class with index to ten, peaks to four, and
height to 220 pixels. Then inside, we will
add a motion div. I'm not adding
animation container that we use because I will add a bit different properties
and I don't want to update the component just for
this specific case. I will just use
motion div there. For class names, I will
add absolute position, left to 50%, top to 50%, and translate X by 50%
and translate Y by 50%. Then we will set the animate. Rotate by 360 degrees, transition with duration to 90, repeat to infinity is
linear, and that will be it. Now we will map over
our thumbnails. I will put the thumbnail
one thumb nail two, thumbnail three, thumbnail four. And like this for
all the thumbnails, there I will do map, and I will put there
thumbnail and index. So thumbnail will be the name of the item in the array
and index the position. And inside, I will start
with the variable for angle where I will
divide index by four, multiply by two,
and by math dot BI. By this, we will spread the thumbnails
evenly in a circle. Then variable for radius, I will say there are 750 and then return where
I will return a dif. For this div, I will set
a key that will be index. I will set a class name
that will be absolute, and I will set the style, and that will be transform
to translate -50% and -50%, rotate where we will again
multiply angle by 90, divide by Mv dot PI, and we need to put our degrees. We can also close this like this and also after we need
to put a translate, where we will again
use these radios and pixels and we can continue inside where we will create another div and this
div will hold an image. And this image will
have the source of a thumbnail of thumbnail, and the class name of width to full height to fool
object to cover opacity 2.9, and
that will be it. For the styling of this div, we will put there a relative
class with 480 pixels. We will group it. Now we
can already see there. The thing we need to do is
to put there rotate 90, and that's basically it. Now we can decrease the
width, maybe even more. 340 pixels. And we can also
decrease the radius. Let's use 650. Now we need to move this a bit
down, but before we do it, let's also add some
text to this section, and this text will be
below this motion div. And there actually, we
need to update this a bit. Let's say we can
leave it like this, but there we will
create the div where we will set absolute
position top -50%, left zero wi full heights
to 1,500 pixels and x auto now let's take the div and wrap this
wall motion div. Now format it a bit. Yes, that's how
it should be now. So you will see in our section, we have the thumbnails. And the last thing
we will do there is that below these two divs,
we will add a new one. Inside, we will add Heading
two, test your thumbnails. And below, paragraph,
experience your thumbnails in a dynamic review environment before going before going live. Now, text center to styling. For heading two, we will at
text five Excel, font, volt. And actually, I didn't
do Excel there. We can make it more responsive. So let's start with
this for medium screen. Otherwise, let's do the text three Excel and text for
Excel for small screen. For the paragraph, we will use the class
names with text large, text muted foreground, maximum width to Excel and mix
auto, maybe even large. Yes. And also, let's put there space Y two. This
should be fine. There we will input the images of the thumbnails
we want to show, and then it will create
this rotating animation. Let's open footer. There we will export function
footer with the return. Put it onto our page. For the Futer, we will
first import link, and we will also import
the animation container. Now in Putter itself, we will do the Putter tag and there the classes we will
add will be margin bottom, relative border to top and border to border
with 0.4 opacity. Padding top, we will set to 16, betting bottom to eight. On medium screen, we can reset it and horizontal
padding to six. On large screen, we can
increase it to eight. We can set it to full, and we will use background
gradient bottom from transparent to background with 0.8 opacity
and backdrop blur small. Now inside, we will
create a di for this div, we will put maximum weight
of seven Excel with Amex auto then for another div, we will create, we will put
a grid layout with Gap 212, Excel and above, we will set grid columns to three
and also gap to eight. Then inside, we will do animation
container with Dla 2.1. And inside, we will put a span
with Tumbernail reviewer. There we will put the
styling of text Excel, font bolt and below this
animation container, we can continue with
a di to this day, we will set the grid layout
with grid columns two, gap eight, and on
Excel and above, we will set coal span to two. This means this will take specific columns on Excel
screen size and above. Then inside, we
will create a div. In this day, we will create
animation containers, so we can do the first
one with also a second one and there we will
set medium screen above, grid layout with grid goals
two on medium screen above, and also some gap. For the container, we
will set a delay 2.2, and the content will
be heading three with previewer then an ordered
list with list item, link that we had to use two specific section,
for example, steps. For Link, we should also have HRF and the class name
that can be on Hard text, primary, transition,
colors, and duration 200. Now we can copy this list
item, paste it below, and instead of steps, we will put their pricing. For the nard list, we will put their margin
from top four space y three, text small and text
muted for ground. Now we have it there, and
next thing what we will do is that now we will offset
sling for the previewer, which will be text small, phone semibolt and
text foreground. And we will basically copy
this animation container, put it instead of
the second one. There we can increase
the delay to 0.3. We will change the
previewer to socials, steps to Facebook and
pricing to Instagram. Then we will take this Valdiv and we will paste
it right below, so we will create
additional two lines. Let's put there 0.4
and 0.5 as a delay. And also, let's put there
instead of previewer contact, instead of steps
support and delete this pricing so it
can be like this. And for the last, we
can put about us, and there something like privacy policy and
terms and conditions. Now, let's save it and
check it on the page. Let's see if
everything is right. We have the introsection
with the steps. We have the demo, animation where we are showing the
demo of our application. Frequently asked questions
with this interactive section, pricing, call to
action and the footer. Now, of course, we also want
to test the responsiveness. Now, the only issue that is creating the blank spaces around our page on a mobile screen
is this demo section. So we need to go into VS code, and we need
to fix it there. Let's put it there into this demo component in this motion div that
is wrapping the image. With two fixed 300 pixels, and mix auto and
on medium screen, we will set With two full. Let's scroll through the page
and see how it looks like. M
20. Landing Page - New Navbar, Updates: And now we will also
create a better Navbar, not a placeholder one
we had on the start, but still it's good.
You can keep it. If you don't want to do this
upgraded version with me, the functionality
will be the same. First, in the Navbar component, we will use client, and then we will
import a few things. We will start with the
link from next link. Then importing the mode
toggle from Team Toggle. Then we will import
signed in from Clark, also signed out sign in button, signo button, and use user. Then we will import use State
and also we will import menu from the Lucid React and X. Also, we will import
animation container. Then we will do
export const Navbar. There we will create a
variable as signed in. And we will use use user. For this use user, it will basically check if we
have a user from Clark. But if you don't have clerk yet or if you're just
doing the front end, you can do there just True. But then you need to
delete this curly braces. We can do it now
like this together. So hardcore the true
value, and that's it. Then it will work like, yes, the user is signed in, and it's also prepared for your future
implementation of sum of. Then we'll create a constant
with a state variable, so it's open set is open. Defaultly well seduce
state to falls. Then we'll create a
function, Toggle menu, and there will set is open to the different value to the opposite value, I mean. Below, we can do the return, and there we can do Nap tech. Inside the Naftac we
will put the classes of BG background and relative, and that index to 50. Inside, we'll create
the for this div, we will put a maximum
weight of seven Excel, Mx Auto, and sparing to four. Inside this div, we will
put a div that will have a classes of flexbox
layout justify between, we have even spacing
between the elements, items to center, height
to 16 and relative class. Inside, we will do the
animation container with delay 0.1. There we will do link with HF to the desired path and classes of Bedding
two and one medium. We will put there the name of the company. I will
put there SAS. Now for the mobile menu button, we will create a div
inside animation container with delay 2.2. And inside the button where
we will check is open, in case, yes, we will display the icon with height
six and width six. In case now, we will display the menu
icon with height six, and we will also set some
attributes to this button or there we will set on click to call the Toggle menu
function, we created above. Then for the classes, we will set Bedding to two, and then for the label, we will set Toggle menu. Now we can move below. Below, we will create
desktop navigation. There we will set hidden on mobile screen or medium
screen, we'll display it. Flexbox layout
items to center and SpaceX to four to have
some horizontal spacing, then animation container
with delay 2.3. And there we will
check, is signed in. In cases, we will return these two lenksPduct
and also profile. There will be HRF of the desired path and the class name of
Bedding two font medium. Basically, we can copy
paste this there. And in case he is not signed
in, we will display now. Below, we will create a link
that we can just copy from there and put it there
and this will be pricing. That will be displayed every time user doesn't need
to sign in for this. And we can move below
this animation container, create another animation
container with a delay 0.4. And inside, we will create a div with classes of space X four, flex, and items to center. And there will be
the mode toggle. There will be from Clark signed out in case he is sign out, which clerk will check for us, he will see sign in button. In case he is signed in, which again, clerk
will check for us. He will see sign out button. This saved us some lines
of code because now we don't need to check
if he's signing or sign out to show this button. We are checking
the theoretically. But yeah, you have basically there are two options how you can do it. W is signed in, where
you will check it there, and then in case yes or no, you will show this or with
the text sign out or sign in, where you will then display
the content inside. So it's true that we could tally get rid of this
and put this text, signed in and then put
there these links. But I believe there
are these two options, how you can do this
via this condition or via the clerk text if you want to use clerk
for authentication. And there we will create a div that will be for
the mobile navigation, and there we'll put on
medium screen hidden, fixed, inset zero,
that Index 40, and we will check is open
with turning operator. In case it is open, so the value is true,
we will do nothing. In case the value is false, we will do pointer events, none. So there are no so there
are no pointer events. Then inside this div,
we'll create another one. But just above this diff, we will create a dip that
will just hold the class. And in this class,
what we will do is that we will set the absolute position with inside zero, background to background
with 0.8 opacity, backdrop blur to small, transition opacity,
duration 300, and we will set there is open. In case, yes, set opacity 100. In case no set opacity
to zero. Like this. This is empty div, so just close it on the
end of the line. So there we will set
absolute position, top 16, left 16, right to zero, Background
to background, border to bottom, border to border with 0.4 opacity,
shadow to large. And for animations transitional, duration 300 is in out. We are still not finished
with this class. Let's continue. There we
will do the dollar sign, and insight we will do, again, the Turner
operator check. In case it's open,
we will execute translate Y zero
and opacity to 100. Fourth, we will do translate Y, full and opacity zero, so it gets away from the screen. Inside this div, we will call the animation
container with D 0.2. There we will do a
div with peaks four, PT, two, being bottom
three, space Y one. And inside, we will
check is signed in. And in CS, we will again show these two
links we have there so we can basically copy this
condition like this. And below the pricing link, which we can also copy. Then below, we are not done yet. We should also copy this. So basically the wall content of this animation container, we had there on the desktop. Let's use there also
some bedding from top. And now I see we
have there the icon. So let's go to the
animation icon. There we need to set
medium screen and above hidden and that index 250. And I will now open
the menu navigation and we can see there this
should be styled a bit. This should be
styled differently. So there we are missing flex and flex
direction column and also left zero, not 16. And there we will
need to add HRFs. So let's do dashboard. For profile, we will
do dashboard profile. Pricing is just pricing. And the same things here, dashboard dashboard with
profile and pricing. Let's go to the global dot CSS and make the gradient
text a bit more shiny. I would put something like this, then something like this
and something like this. Also, I would go to the hero and I think three easy
steps there gradients text, maybe decrease the opacity 2.9. And last but not least, we will create a
button glowing effect. Let's go to our ID, and in our ID, we will open
button glowing effect. There we will start
and it won't be that long we will
just import a link. We will import an
icon, Chevron, right. And we will create an interface there for button glowing props, where we will need to define the text that should
be as a string, and we should have the text
every time, of course, because there should be
something on our button and HRF, that is not mandatory, but would be a string
if there is any. Then we will create
export default function, button glowing, where we will take
the text and HF as a pro button growing props. And we will do return there
inside this function. What we will do there is a div. Inside this div, we will
add a padding to eight item actually flex box layout
and then items to center with ify center to center it
horizontally and vertically. Inside this div, we will
create the link for the link, we will set the HF to HF
and some class names. We will group it, we will make
it relative in line flex, items to center with
Gap two, rounded full, background, black,
horizontal padding to four, vertical padding to two,
text small, text white, transition to all and on our background white
let me put it on another line so you can see on our background white
with 0.05 opacity. Now let's say the Spen tech. This Spenteg will
be actually empty, will hold only the class name. For the class name it will hold absolute position in
set zero rounded full, then background gradient to right from this color
code that I have there. So it's FFE 56 via
another color code, which is FF 00 FF and
two last color code, which is 00 and four times F now let's set
there also some opacity. We will set there opacity
to 70, blur to small, transition to all, and
also on a group however, we will make opacity 100. Let's go to our hero section. And in our hero section, there above the
terminal previewer, we will call the button
glowing as a prop, we will input there the text, starting price available 30%
of with HRF that won't fill, and now we will have
it on our page. Of course, we still need
to add the styling. So let's go to button
glowing effect, and let's finish
there there below the Spentec I will
put another one. Also without any content, just put there class name
with absolute position in set 05 then round it full
and background to black. Below, I will put a Spentec, but now it will have a content. It will also have a classes of relative flex items to center, Gap two, and font medium. Inside, it will
show the text prop, and also next to the text, it will show the
icon Chevron right. And for the class names,
it will have size four, transition transform then group
Her with translate X 0.5. Now we can go to our page and
we have there the button. You can see how it's working
on Her and we can also check it for the responsiveness. There we have it. We need to update
the tonomble screen, and let's put there
text to center. Also, I see in the hero section, we need to fix this heading.
We can just do there. Text to center is that there we will set maximum weight to Excel, have it already there. So let's set there from a
medium screen or from Excel. Otherwise, maximum weight, let's set too large, maybe even less. Yeah, we can leave it on a small and there we will
change it to Excel. Then it will look like this on mobile or smaller
screen devices.
21. Profile Page: Can move on and do
the profile page. And during the profile, we will set our channel name, and the channel name will be automatically populated there. And it will be saved
there for our user. So once they will set their channel name
in the profile tab, they will have it there
already when they will log into the application
and we want to use it. So they will be just
filling the title, and then of course,
the thumbnail. Let's now go to the Schema dot prisma and
there we will add a new value. We can do it there
below the name. Let's do it like channel name. It will be string and
optional. Now I will save it. I will do NPxPrisma DB push. Um, that will push
it to my database. Now in my table, I also have this channel
name and I can work with it, and then I will go to the profile page and we
can start coding there. We will start with
few imports there, first Prisma from our lip DB, then off and current user
from Clark next J server, redirect and revalidate path. Then we will start with defining an asynchronous function to fetch the user data
from the database. Let's do asynchronous function, get the data user
ID as a string. And inside, we can start. First, we will query
the database for a user with a given user ID. Let's save it into
the user variable. There we will await
Prisma dot user find Unique there where
the ID is in user ID, and we will be selecting the channel name because
that's what we want, so we are able to
actually set it. And we will return
user dot channel name in case it's not found, we will return empty string. We can continue with defining the main profile page component also as an
asynchronous function. So export default async
function profile page. And first, we will get the
authentication session. So user ID from off, which we will be using
from Clerk Library, and we will retrieve the
authenticated users information and save it into
the user variable, so we will await current user. That is also from
the clerk library. Then we will check if the
user is authenticated. We will be checking if user
ID or user is not true, we will redirect
to a sign in page. Then we can continue with
fetching the user data from the database and we will save it into the channel
name. We will await. Now we will call the function
we created earlier there, get data and the parameter we will send there
will be the user ID, which we are getting
there from the clerk. This will then get the user ID. Query the database and return channel name
of this user ID, and we'll save into this
channel name variable. Now, you will define an
asynchronous function to handle the form submission that
means when the user will want to update
this channel name. So let's do asynchronous
function, post data. We will start with
marking this function as a server action
with use server. That means that this function will run on the
server side only, and it will allow
direct database access. Then we will get
the channel name from the form submission, and we will save it into
the variable channel name. So form data dot G channel name. If you are curious about
this, form data, basically, that's the input user will fill into the
textbox of the form. We will go in a second. Then we'll update the user's channel name in the database. So we will do their await
Prisma dot user dot update, and we will be updating where the ID is
user ID is string. And data will be the
channel name set to channel name Oops, a string. And after this is done, we will revalidate path on
dashboard with slash there. Nice. We now have also
post data function. That means we now just need to return the TSX for
rendering the profile page. So we will create the return. The we'll create there we
will start with the Ditech. For this dftech, we will start setting the
maximum width to Excel, and mix order to center it, PY and Px 24 to
add some bedding. Also, important step
we need to do is that we will go to the profile page. So in our navigation, click
there the profile page. Site cannot be reached. Let me see why. Yeah, because I need to do NPM run Depth first as
I somehow closed it, there you can see
nothing is there, but soon this will be changed. So let's continue in the coding. The next thing that we will
do is to add some page title. So I will do heading
one with profile, and I will set there
classes of text for Excel. Font extra bolt, tracking
tight, and on large, I will increase the text
size to five Excel, let's say, I will some
margin to bottom. We can do six. Then
I will continue with a div that will be there as a card container
for the form. Into this div, I will
put a form itself. First, let's put
there some classes. Let's do round it large border, background to card,
text to card, foreground, and shadow
small and some padding. Something is already happening
on our profile page. Let's continue there
with the form. And for this form, the action will be post data. Then we will create a div there. We will set there space Y four. Inside, we can
create another div, set there space Y two. In this div, we will
create a label. To this label, we will add first that it's HTML four to tie
it to the channel name. Below we will do the input. Let's put there
the label itself, channel name, and now we
need to do the classes. For the classes, we will do text small, font, medium, leading, none, and I think that's it. Below we will do the input. We can actually close it there, and attributes we will
add will be type of text, then ID to channel name
then name to channel name. Then on the default value, that will be the channel
name in case user will already save this once. He will have it
there for next time, and when he will want to
change, it will still be there. Then we will set
the class names. Let's do the flexbox layout, height to ten, width too full, round it too large, border input, BG background. Then some PX and PY, what else? Text too small, and
now below this, DIV but still above this one. Let's check it. We have one div that
holds label and input and the second div that will hold this label with input, and there we will hold also
something like submit button. We don't have the submit button yet, but we will fix it now. So let's open the
file exxplorer. There we will go
into components. We will create a new file. We will call it submit button. And in the submit button,
we can start creating the submit button that we
will use on our profile page. First, we will define there
it's a client component, then we will import the use
form status from react doom. Then we will import the button. We have there from Chet CN, and we will import loader
to from lucid react. We'll start with export
function submit button, and inside, we will create
a new constant pending, and we will use
form status on it. So if this form will be pending, we'll be using this variable. Now let's do the return
inside this button. We will check the
pending variable. In case it's true, we will
execute this position. In case it's false, we will execute this position
that will be just submit. But in case it's true and
the form is really pending, we will do the load there too. With classes of height
four with four, then animate spin and
margin to write two. Below, we will put updating. Then we will go to
our profile page. We will start typing
their submit button. We will import it. It will now get to our page. You can now see we
have it also on the layout. Let's now test it. Let's put there testing
channel name, I submit. You can see it's updating.
The field was really saved. Testing channel name.
22. Displaying Channel Name on Dashboard: And what we need
to do is to go to a dashboard page,
Abashboard page Tsix. And there we will now
send this channel name we have in our database to
this prop channel name saved. So we need to first
get it on this page, and then we will send it there. Let's start about the
dashboard function, and there we will do
asynchronous function. Get channel name, where we will send the user
ID as a string, and there we will save into the user weight Prisma
dot user dot Find Unique, where the ID will be user ID, and we will select the
channel name and we will return the channel name in case it's there,
otherwise, ampithe string. Now we have the function,
get channel name, and we will scroll there,
and above the return, we will create a
variable channel name, and we will evade the get
channel name function where we will send the user ID,
we are getting there. Now we can take
this channel name and send it as a prop there. Now we can test it.
Let's go to our page. Let's first go to the product. There you can see
the channel name. Let's go to profile.
Let's change this. I will click Submit. Now I will go back to product, and you can see it's there. Let's change this, which
I now just changed. So then I will fill there
just some test video. I will put there the thumbnail and is working even
with the channel name. So this is it also
for the profile page. Now it's time to
test our website. We will try to sign up. Then I will continue
with Google. After we sign in, we can see that we are not
subscribed yet, but also new items
in our Navbar. These are for the
product itself, pricing and also
profile where we will set the channel name that
we will use in the product. Let's click on subscribe. There we will fill in the data and we will get onto
payment successful page, and there we have our product because now we are subscribed
to the application. There you can see we can set the title for the video card, then the tabine itself,
and the channel name. For the channel name,
we will actually go to profile and as we will
now be using this, we will set there our
channel, something like this. I will submit it. Now I
will go back to product, and there you can see
I have it prefilled, and every time I will log into the application, I
will have it there. Now that's the previewer itself. I will put there
thumbnail for the title. I will also put there something, and then I can see the video
card with the thumbnail. Now I can randomize the order, and also I can change this to
tablet view or mobile view. And if you would like to
manage the subscription, we have the button that
will redirect us to Stripe where we can just simply manage it. And that will be it. Simple functionality
for microsaS with one feature to
test out the product. And of course, if
it's successful, there can be more and
more features added.
23. Deployment: Thing is ready, and we
can go that last step, and that will be the
deployment to Arsl. First thing, what we will
do is that we will open a Git Ignore and make
sure we have there and file because we
definitely don't want to upload to get any of our
environment variables. Then you can also
check package dot JSON and make sure that in scripts, you have this set for your
death build and start. Now we need to publish
our project to Get up, so we will publish to GU. Now on Git up, we can
see everything got published and pushed
in case from now on, you do any changes,
for example, there, you will then just stage
it in your source control. There you will put a
commit message update off. Git Ignore, for example, you will commit it, and
then it will get to Git up. And after we will
connect it with Versal, it will get also automatically there because Versal
will automatically run the deployment
round for you and will deploy it to the
live there onvrslot com. You will choose how
you want to log in. I will continue with Git AP. And there on this dashboard, I will click on a new project, and I will set the one
I pushed to Git up. It will be this one. I
will click on Import. And there now you need to set all the environment variables,
where you put the key, which will be the name of
the variable and value, which will be its value. And you will go into your file and from there,
you will take these values. You will put it there,
you will click on Add More and all the values from the clerk to stripe and
so on, you will put there. I put there all my
environment variables, and there is the last
one next public URL. And this one we will fill
with value after we will deploy it with the domain
name we will get from Versal. Now I will click on Deploy. And I will wait until
the build will be done. Now you can see it during the deployment. So
let's wait a bit. We can see that we have error defined but never used
in Stripe route Ts. Let's go to VS code. That means in VS code, we will go to Stripe route and we will check for the error that is
defined but never used. We will just at the
use of the error, so we will put
console dot error. We will put there some message. Webhook signature
verification failed, and we will put there the error. Next error is with use team there we will just
delete the import. Then the button and
link in page TS six. Again, we will
delete the imports. Now the next error was
in animation container, so I will again
open the VS code, and there I will import
also animation props. We had there the type
of ANA for transition, exit initial and animate. Instead of the type of ANA, we will put the animation
props, and for animate, we will do animation props for initial initial for exit exit, and for transition transition. For the other errors, we
will go into input first, and there we will just
redefine this and we will put there type of
input probes to react, and there we can copy paste
this input HTML attributes, and we can delete the
input probes before this. So t's delete it there, save it, and we can move to text area. And in text area, we
will do similar thing. We will put there type text area probes it goes react dot
Tex area HTML attributes, and we will delete
the one before, leave there just this
one, and that will be it. Now for fixing the other issues, you will create a file called nexdot config dotgs and
put there this code. Also, we can remove the dot js. So in this one, we will
set the next config. Next file we will create
is versal dot JSON. And in VrsalJSN, we will put built command and
install command and set there these commands. For the first one, Prisma
generate and next built, and for the second
one NPM install. Then we will go into
package dot JSON, and there below the
Lind in script, we will also add post Install and set there Prisma generate. And what we'll do also
is that in package JSON, instead of that build command, you will put there for
build this command, Prisma generate and next build. After you have all
these changes, you will go into source control. You will stage them all, put there some message,
and commit it. Then you will go
to Versal and you don't even need to start
the new deployment. You just click on your project, click there on Deployments, and there the new
build should start. If not, just repeat the process deploy again or find the
button for redeploy. Everything should be fine or at least with my code and
changes I shown you, everything was working for me. What we will do is that we will take this
domain and we will go into our project.
They're into settings. They're into
environment variables. I will just click there
on the new variable, and I will put there
the value of the domain that I copied and
you also need to put there HDDPS Next public URL
was the name, I believe. Now we will click on Save it got edited and just
a small heads up, make sure database URL and
direct URL are without the quotes on the
beginning and on the end and it's just
pasted like this. In our project, we
will go to settings. There we will go to
deployment protection, and we will turn this
off. Now we will save it. When setting the
endpoint in clerk, we also need to do their API webhooks clerk and
save it like this. And also, right
after you deployed, make sure you are testing this with the user
that is not in both clerk or Superbse Just with a brand
new Google account, for example, that you don't have neither of them to
test this properly. Now, we will test
also the stripe, so I will do stripe login. And there I will need to put the domain with API
webhooks, stripe. And now on the pricing page, when we are trying to
subscribe, we got an error, and that's because we have some issues with this
success and Cancel URL. Let's actually go to lip slash ScripTs and at
there these new changes. Check there for the domain URL, and at there equals true at
the end of the success and Cancel URL and also
metadata customer ID. Then in app pricing page, you will create this new
variable for domain URL. Then we will check
for the domain URL. In case it's missing,
we will throw an error and also instead of this domain URL
that was there in the subscription URL for Stripe, we will set domain URL to just domain URL now
that we set there. With these two changes in app pricing page dotix and
also in stripe dot Ts, there you can see it in the
actual repo by the way, we will go to pricing page DTAix and there are
the other changes, and there we are
setting the domain URL. Now we will make
sure that you commit all changes and push
them to your repository. Then you will wait there
for the deployment, and now we are ready to
test even the stripe. I will click on Subscribe. There, I will fill
the information. And after successful payment, we can see we are now subscribed and we can
use the application. And we have our subscription
active in SUPAbase. And from my side, that's
it for the tutorial.