Welcome to this week's article 👋, where we would be continuing of from last week's article about my thoughts on Remix whilst creating a Remix task tracker app. Without further ado, let's get started:
🔧 Rework:
It was time to add the login functions. I decided to mix things up a bit for the authentication, I used bcryptjs
instead of Supabase like I had planned and instead of a google sign in, stuck with the native email/password authentication method.
Let me draw a rough blueprint for the authentication:
- We would have a login page that allows users to either Sign Up (register) or Log In.
- Validate the users based on their choice, if
register
method:- Passwords must be equals to or greater than 8 characters
- Valid email must be used (it must be unique in the database)
- If the method is
sign-in
:- The password must be correct
- Email entered must be correct
- If validation process is successful, redirect them to the task-tracker page.
Seems good enough to me, let's start the build 👷♂️!
npm install @prisma/client
npm install --save-dev prisma
npm install bcryptjs
npm install --save-dev @types/bcryptjs
I created a prisma
folder in my root directory and in it, created a schema.prisma
file. This is where our database schema(structure) would go.
Before you are wondering what database, I am using railway to host my PostgreSQL database. It is free and great for your little side-projects that require a running database.
I have already provisioned a new PosgreSQL database (call her whatever you want), and now it's time to connect our Prisma to it!
Create a .env
file in your app root directory and create an environment variable called "DATABASE_URL". It is this url that would allow prisma to connect to our database seamlessly. Head over to your railway dashboard and navigate to the "PostgreSQL" tab, in select the "Connect" tab and copy the Database Connection URL
Paste the URL in the .env
file (as your DATABASE_URL) and you can get started with Prisma!
In the schema.prisma
, I connected to my railway app and created a model for the database:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique()
password String
icon String?
createdAt DateTime @default(now())
tasks Tasks[]
}
model Tasks {
id String @id @default(uuid())
title String
description String?
status String?
reminder Boolean @default(false)
priority String?
deadline DateTime
createdAt DateTime @default(now())
updatedAt DateTime @default(now())
userId String
user User @relation(fields: [userId], references: [id])
}
I created to tables, one for the user and the second one for the tasks, this is a one-to-many relation in the sense that every user would have it's own table of tasks which would contain a lot of tasks (One user -> Several Tasks).
In the User
table, we have an id (IDs are a must for every record in a table) that's a unique user id (uuid), and an email that must be unique. Also have a password field, an icon field that is optional (indicated by the ?
icon after the type). A created-at
field and a Task field (that's more or less, a table).
In the Tasks
table, the important fields are the id, the task's title, an optional description and deadline (which is our expiry time) and the most iportant, linking our User
table to the Task table (Prisma has an explanatory guide on single-to-many relationship model). The rest are little details I intend to add to the app later to give it some spice.
You can run npx prisma studio
to view live changes to your table and edit the database yourself!
I created an authentication handling action in my index.tsx
(to avoid a messy post layout, I would refrain from adding all the code changes and instead link the repo at the end of this article) and linked it to a custom Remix <Form>
. Let's rewind a bit on something, I am storing the user's password in the database? Yes, and we are going to use bcryptjs
that we installed earlier to hash our passwords so no one would be able to decipher it (even the admin!)
If you think you can easily break a hashed password, try this:
- Hashed version of password "password" is: $5$MnfsQ4iN$ZMTppKN16y/tIsUYs/obHlhdP.Os80yXhTurpBMUbA5 using the "SHA-256 crypt" hash type.
- Using bcrypt hash type, the same password would end up as $2a$05$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe. Not really an easy thing to crack.
After setting up my Form, it was time to style it and test it out.
Form look with some basic styling
Signed In!
Ok, now we have successfully signed in. Let's add a logout function. That can be easily done by creating a logout
route and then just having a loader that redirects to the login page.
//logout.tsx
import type { ActionFunction, LoaderFunction } from "remix";
// import "redirect" from Remix
import { redirect } from "remix";
//import our logout function
import { logout } from "~/utils/session.server";
export const action: ActionFunction = async ({
request
}) => {
// run the logout request
return logout(request);
};
export const loader: LoaderFunction = async () => {
// redirect the user
return redirect("/");
};
🧳 Wrapping Up:
Let's wrap up the basic function of our App. We need to save and get the user's tasks when they edit it. I decided to use real-time saving. Meaning each time they add or delete a task, it gets updated immediately, meanwhile, the deleted tasks would get deleted permanently each time the user signs out as we won't save it (we can cache it for another time though 🤔).
We have the basic create + delete set up, but it takes a while to register. Let's give the user some indication that something is happening
And that's it for a basic task tracker app! Time to push to github and deploy. I hope to add extra features to it later as a personal challenge.
That's the end of the article series. This app was super fun to make and I am enjoying Remix more, issues I faced while making this app were more from prisma's end (Ha!), an example is weird disconnection from the database and random schema generation. I think Remix is good to go for a full-stack -large-scale application. Remix currently has a huge drawback for me currently, and that's a problem with importing ESM modules. Good news is that is currently getting fixed by the Remix's team, for now, there are work arounds that might successfully or unsuccessfully import the ESM module. Besides that, Remix all the way for me 🚀!
Like always, have fun learning and coding and don't forget to take breaks! Till next time 👋.
Top comments (0)