Real-time parcel tracking services are widely used in logistics companies worldwide. Both companies and customers can benefit from a viable service that provides tracking services and updates a parcel's status in real-time.
Appwrite is an open-source backend-as-a-service platform that provides developers various valuable services and APIs for building applications. Appwrite offers a Realtime Servicethat developers can use to build a parcel tracker that updates a parcel's status in real time without refreshing the page.
This article demonstrates using Next.js and Appwrite to create a real-time parcel tracking service. With Appwrite, you will build a real-time parcel tracker that lets you update the parcel's status directly from the Appwrite console.
GitHub
You can find the complete source code here.
Prerequisites
To follow along with this article, you'll need the following:
- Docker installation
- Appwrite installation
- Terminal
- GitHub account
- Basic knowledge of Next.js
- VS Code or your favorite code editor
- Tailwind
Getting started
Begin by clicking on Getting Started on Appwrite and running the commands in your terminal to install Appwrite. After installation, you should receive the following message:
Setting up the project on Appwrite
To set up the project on Appwrite, navigate to the URL where your Appwrite server is running by combining the port and localhost you specified when installing Appwrite as localhost:<your port number>
on your browser.
Next, sign up to create a root account for your project:
After successfully signing up, you will have access to the Appwrite Console for creating your project:
Click the Create Project button and provide a name for the project:
Creating a database
For your project, you need to create a database to store the data for your application, which Appwrite's Realtime service will monitor for status updates.
Navigate to the Appwrite console's menu and select Database:
Following that, create and name your database:
Creating your first collection
After successfully creating your database, you can now create your first collection to store the parcel by clicking the Add Collection button and naming the collection:
Creating a second collection
Create a new collection to store the Parcel events (which refer to the state of the parcel during delivery) by returning to your Parcel database and clicking the Add Collection button:
Adding attributes to the collections
In the first Parcels collection, add Attributes to store information about the parcel:
Add each of these attributes according to their data type:
parcel-name, customer-name, weight, quantity, time
Refer to the second ParcelEvents collection and add attributes for the parcelID
, status
, and time
.
Creating an index
You need to create an index to query data from the ParcelEvents collection. Navigate to the Indexes tab and click the Add Index button. Name the index, set the type, and choose the parcelId attribute from the list of attributes:
Setting collection permissions
Navigate to the Parcels collection, click the Settings tab, and then click the Add Role button under Permissions:
Then, for the role, select the "any" option and enable the Create and Read permissions before clicking Update:
To set permissions on the ParcelEvents collection, go to the Settings tab and add the following roles: Create, Read, Update, and Delete:
Next, you'll use Next.js to begin building the project.
Building the project
Refer to the documentation to start building the project with Next.js, or simply run this command:
npx create-next-app@latest
When the command completes successfully, open the directory in your code editor, and your project structure should look like this:
Setting the environment variables
In the root directory, create a **.env**
file to store the environment variables for the following:
- API Endpoint URL
- Database ID
- Parcels collection ID
- ParcelEvents collection ID
- Project ID
To create the environment variables, you need to add "NEXT_PUBLIC" as a prefix, which tells Next.js that the environment variables belong to the client side:
To obtain your API Endpoint, navigate to the menu and select Settings, and copy the URL:
Return to the menu and select Database to find your Database ID. Navigate to the Settings tab of your Parcel database and copy the Database ID:
Next, select the Parcels collection on the Collections tab, then go to Settings and copy your Collection ID:
Copy the Collection ID for the second ParcelEvents collection:
To obtain the Project ID, return to the Home page and select Settings, then copy the Project ID:
Adding Tailwind CSS to the Project
We will use the Tailwind CSS library for this project. Install and initialize Tailwind in the root directory of your project by running the following commands:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
After running these commands, the "tailwind.config.js" file will appear in your project directory.
Open your code editor and paste the following configuration into the tailwind.config.js file:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./pages/**/*.{html,js,jsx}"],
theme: {
extend: {},
},
plugins: [],
}
Paste the following code at the top of the globals.css file in the styles folder:
@tailwind base;
@tailwind components;
@tailwind utilities;
Adding Appwrite Connection and Configurations
To install Appwrite Client in your project, run the following command in the root directory:
npm install appwrite
Create a Utils folder in the root directory containing two files: appwrite-connection.js (for connecting your project to Appwrite) and config.js (configuration file that will centralize the data in the .env file).
Add the configuration defined in the config.js file in the GitHub repository.
Creating the landing page
Replace the code in the pages > index.js file with this code. You are creating a functional component Home()
in the index.js file that does the following:
- Creates
isLoading
,parcelID
, andparcel
states. - Creates a function called
getParcelDetails()
that accepts the parcel ID as atracking No
parameter and performs the following operations:- The
setLoading()
function initially sets theisLoading
state totrue
on the calling of thegetParcelDetails()
function. - Queries the database to retrieve the parcel according to the tracking number that the user provides as input.
- Saves the response in the
setParcel()
state and routes and carries the data to the tracker page (where users can view the parcel status). - Any error message will appear as an alert and log to the console. After a successful process, the
setLoading()
state is set tofalse
. - The
setLoading
function will set theisLoading
state to true once the operation is complete. - The condition in the '' section checks whether the
isLoading
state is true or false. When true, the<input>
tag retrieves the tracking number the user provides as input and uses thesetParcelID()
function to set theparcelID
state to the tracking number. - When the user clicks the
Track Parcel
link, theonClick()
event calls thegetParcelDetails()
function with theparcelID
as a parameter.
- The
Creating the tracking page
In the Pages directory, create a new file called "tracker.js" that will contain real-time updates on the parcel, including the parcel's status from ordering to delivery. In your tracker.js file, insert the code written in this repository.
This code does the following:
- Creates a
**Tracker()**
functional component, which does the following:- Creates a
notifications
state to store the parcel events and aparcelData
state to store information about the parcel.
- Creates a
- Creates a
getParcelEvents()
function that accepts theparcelID
as thetracking No.
parameter that implements the following:- Fetches the list of documents from the ParcelEvents collection according to the
**ParcelId**
. - The
Date
variable maps through each document in the list. - The
setNofications()
function updates the notification state with the data.
- Fetches the list of documents from the ParcelEvents collection according to the
- The
registerSubscriber()
function listens for the real-time events on Appwrite by subscribing to thedocuments
events. For every trigger in thedocuments
events, the callback calls thegetParcelEvents()
function, passing in theid
from theparcelData
state. - The
useEffect()
monitors therouter.query
and executes a callback which sets theparcelData
state, calls thegetParcelsEvents()
function, and calls theregisterSubscriber()
function.
Testing the project
To test the project, add data to your Parcels collection and click Add Document:
Then set the following:
Afterward, click Create and copy the "$id":
Next, select the ParcelEvents collection and create a document using the "$id" you copied:
Click Create, and you should have the following document:
Start the development server for the project by running this command:
npm run dev
Visit the URL "http://localhost:3001" to view the application:
Conclusion
This article demonstrated how to build a real-time parcel tracking service with Next.js and Appwrite.