A timeline visually represents the work required to finish our project. It displays the dates that each activity was completed so we can monitor our progress. On the other hand, it may also convey what is required to achieve deadlines, making it more straightforward to manage expectations and assign priorities to projects in the long term.
The post will teach us how to build a timeline tracker with Cloudinary and Xata in a Next.js application.
Cloudinary provides a secure and comprehensive API for uploading media files fast and efficiently from the server side, the browser, or a mobile application. We can upload media assets using Cloudinary's REST API or client libraries (SDKs) which makes integrating with websites and mobile apps more accessible.
What is Xata?
Xata is a serverless data platform that enables us to manage, scale, prevent downtime, cache, and maintain our database to improve our development workflow. Additionally, it offers a relational database, an effective search engine, and much more.
Prerequisites
Before getting started with this tutorial, we should have the following:
Basic understanding of ES6 Javascript features
NodeJs installed in our PC
Knowledge of React and React hooks
Yarn or NPM package manager
Project Setup and Installation
To proceed, let us clone the starter project in our preferred directory with the git command below:
Run the following command to install all dependencies using the yarn package manager.
yarn && yarn dev
Or Run the following command to install all dependencies using the npm package manager to start the project on http://localhost:3000.
npm install && npm run dev
We should have something similar to what we have below.
Creating and Setting Up Xata
In this section, we will set up a Xata profile by signing up for a new account or login. We will get redirected to our dashboard after successful sign-up, as shown below.
Next, we will click Add a database, enter our preferred database name*, and* clickcreate. We will be redirected to the database page similar to what is shown below.
We will create a table called users to save all the records of users that signed up on our platform, as shown below.
Add the following columns to the users table.
Column Name
Data Type
Unique
firstName
String
[ ]
lastName
String
[ ]
email
Email
[x]
password
String
[ ]
We will repeat the above process to create a new table called timelines with the following columns;
Column Name
Data Type
Unique
Table
title
String
[ ]
-
description
String
[ ]
-
timeline
String
[ ]
-
image_url
String
[ ]
-
user
Link
[ ]
users table
Next, we will connect our app to the remote Xata database we created using the following command below.
# Install the Xata CLI globally
npm i -g @xata.io/cli
After installing the Xata CLI globally, we will use the following command to initiate the database instance locally.
Stop the application from running in the terminal and run yarn dev or npm run dev to restart the server.
Implementing User Authentication
In this section, we will implement user authentication functionality to help users register and login on to our application to create a timeline.
Registration Functionality
Inside the pages/api/ directory, update the register.js file with the following code snippet.
# pages/api/register.js
import { getXataClient } from "../../src/xata";
import { promisify } from "util";
import bcrypt from "bcryptjs"; // bcrypt to hash user password
// Hash password with bcrypt
const hash = promisify(bcrypt.hash);
// initialize XataClient function
const xata = getXataClient();
export default async function register(req, res) {
// Get user data from request body
const { firstName, lastName, email, password } = req.body;
// Fetch user from database using email address as unique identifier if it exists
const userExist = await xata.db.users.filter({ email }).getFirst();
// If user exists, return error
if (userExist) {
res.status(400);
throw new Error("User already exists"); // throw error if user with email already exists
}
// Create a new user in the database
const user = await xata.db.users.create({
firstName,
lastName,
email,
password: await hash(password, 10),
});
res.json({ message: "Success" });
if (!user) {
res.status(400);
throw new Error("Invalid user data");
}
}
In the code snippet above, we:
Created a function called register with req and res as a parameter
Extracted firstName, lastName, email, and password from the request body
Check if a user already exists using their email address
Hash the user's password using the bycrypt package
Create a new user record in our database using the Xata client getXataClient and return a success message if the user doedoesn'tist
Next, please navigate the register.js file under the /pages directory and update it with the following code snippet.
In the code snippet above, the handleSubmit function sends the user data to the register API we created earlier, allowing us to create a new user in our database.
Let's head over to the Navber.js file in the components/ directory and update it with the following code snippet.
In the code snippet above, we added isAuthenticated props and a check to only display Register or Login to Create a Timeline when a user is not logged in.
Next, we can update the index.js under the pages/ directory with the following code snippet to implement the isAuthenticated data and retrieve all the timeline records created in our database.
Heading over to our browser, we should have something similar to what is shown below. In the following section, we will implement the Login functionality.
Login Functionality
Similar to registering users on our platform, we will validate and log them into our system after registration. Let's update login.js in the pages/api directory with the following code snippet.
In the previous steps, we successfully implemented user authentication; we will proceed in this section to implement the upload functionality to allow logged-in users to create timelines.
In the upload.js file under the pages/api directory, let’s update it with the following code snippet.
In the code snippet above, we implemented an API that allows users to create a new timeline, upload it to Cloudinary and save it into our Xata database.
Next, we will update the upload.js file in the pages/ directory to consume the upload API we just implemented with the following code snippet.