Build a real-time parcel tracking service in Nextjs
Published: 2022-11-22 10:48:45

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](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba) is an open-source backend-as-a-service platform that provides developers various valuable services and APIs for building applications. Appwrite offers a [Realtime Service](https://appwrite.io/docs/realtime)that 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](https://nextjs.org/) 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](https://github.com/debemenitammy/Parcel-Tracker). 

## Prerequisites

To follow along with this article, you'll need the following:

- [Docker](https://docs.docker.com/get-docker/) installation
- [Appwrite](https://appwrite.io/) installation
- Terminal 
- [GitHub account](https://github.com/)
- Basic knowledge of [Next.js](https://nextjs.org/)
- [VS Code](https://code.visualstudio.com/) or your favorite code editor
- [Tailwind](https://tailwindcss.com/)  

## Getting started

Begin by clicking on **Getting Started** on [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) and running the commands in your terminal to install Appwrite. After installation, you should receive the following message:

![](https://lh6.googleusercontent.com/SMc_rIHCBNCvSMALZmmph6mywFbVR-koCqywex3fn40QfJqGKxHMEwg2ITbICbwuj84-HUM84TbdTHysqqzOeR-LREL1ysQ6cvyN3lNadrSuGpO5EstirHCrzJaNDeWf4QdlbJgo_r4MxWk3GHm5opWhZPsX8NEi32dT0kJ3wi-oeoIgiz_d03au3w)

### 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: 

![Creating Appwrite account](https://lh5.googleusercontent.com/ydJezfFrXfwtf5UFnAH39oa8-f2AbUxVVguoSndTz23QkTAZluMgPPdHtg9L1MtZ-pl3vVUviDZA_A1SbUmMhM3uwLp7qiIuR_3_KWRGs7SJoe1XsNzkK5fxlW1-qDDPTzW9ix17hTVFgsN1vSP-g-drKI9uEunKnSf2fjkZNEmovfpUxC_ernw89Q)


After successfully signing up, you will have access to the **Appwrite Console** for creating your project:

![Appwrite console](https://lh6.googleusercontent.com/t7XlpdDngTsJYcmZJCeswWmyPHME6VLt364QkZ7PMdLvcYekJbv9ZKT-DWBcqDFjgpH6dJXM9wcWXS6zok0vA3SdZXcwfE1m1oFLShWuP0RtJ4HKvxXbeRG2H0bj_wFtlt5NENZgWYFZD_jo_MFP-747ZYrwq-hsFcG7eMI79ONduswTTscM__KQ_w)


Click the **Create Project** button and provide a name for the project:

![Naming the project](https://lh5.googleusercontent.com/fxjvT_L-m6d3a8GU5ygAKD4qaTzC_SiLA87Z3P6P64gJlzh52WZErpD57Cq5xbRSnTTZMehhmIIqCwvtdUXr_lLgJh-89iX8IszWtBBOKJ5YDlt5WD2rtysJESKtvGIXOcP8z8rXzj_ZG6l1IlDVAadpai777P6-vSpPP39ERZY7qVRwUzihcL-wrw)



### Creating a database

For your project, you need to create a database to store the data for your application, which [Appwrite's Realtime service](https://appwrite.io/docs/realtime) will monitor for status updates. 
Navigate to the Appwrite console's menu and select **Database**:

![Selecting database](https://lh3.googleusercontent.com/8YNJ_ZrIk1V8lSasIN_BhlfrdT2jMmBOqH7a2srHP4j7VgiOk2AI4KfgeBwIOlaVIH2HnMFCI6yytUZj7U0b3UaTGJRxMs6CZQsOC1qgIGL1K5sPFFPFE2ech_B7t4vhK42yrgXUU2o7kbO11weeS2lGhRW3DPy9mOmtak1L6XUmb51bXiusizVcPw)


Following that, create and name your database:

![Creating database](https://lh4.googleusercontent.com/Er-Gh4CeQPmOjBenPT8Z8wm5PNzgxzWWDZLzncD6tsQPGwQh_4dtDylVMhDGwGkj7xgWmQCZ101Zf0TcQ5d6jlRRqgogRI5e3K7QEOV1W_d6SOBAzpgoPbU2vwKBknZpMpdL5C_0vclanqVq0vTzQdEFA6FYKH41xp1rU_41-Zgd_Q3bIbr3CfaKKA)

### 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 first collection](https://lh5.googleusercontent.com/6wvTgX_CmgZ2dZmW0rBAl16vLUmZX8sB3I6m18sM2uGhsGjFdzymBTPWMeMcqGhHTohBczfLfCqv46XJ3eelkXWunAAHzP0BxE8l1R_CX_tRzwBbu3C_tO3JJd44DHlz6isWSSwR2oLKGUI3om2eMMILeO2arzM0RAZ9irqNzt2kWN4YhmOHX5J1Qg)

### 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:

![Creating second collection](https://lh3.googleusercontent.com/7Ujtn9A1qq8TwNlAd0ewRJl-xNsbIzvrfPVX1txvFYBvvhO0dVbIdSkAu2azchHlZXzv9oUsj2hYmDP7uzX9l5il_J6T0sr5g2GpzrmZ2KtzmjIu5LxCgGIZru7ZdGV5w3NqFOIelkhFYScZZYeHvqU3QRfupzvMhg1tY2dT9s7S8sYYrldHkCKqbw)

### Adding attributes to the collections

In the first **Parcels** collection, add **Attributes** to store information about the parcel:

![Adding Attributes to the Collections](https://lh4.googleusercontent.com/7j6ZFlA2mW17toz1unyHPqWP1RVie5nGtJKPaZAMrfyV5zajFXOnU-2LIeXRkSqotYgHwjHVfJwsHvDXFTy0wtyofiyRZ8Twpo8xMRVDnruDPpjGui_kd7oCYH1byJrb7XzbTsKQF171tLWLsPnJWyuEN8lUenykqXdHkGRK_j20tbOZGfvuLDb1gg)


Add each of these attributes according to their data type:

```
parcel-name, customer-name, weight, quantity, time
```

![Adding attributes](https://lh5.googleusercontent.com/gdAS83HZWm0vbs-Bk_hT3liVfzkA3t99of47R5OV-ftFPLPthJaKLfPIXA1fqNOHYiVZqXdRj4CnMCE59LxHUyNHtXBtpKO_c7nZ3I_eJCb1RhG3F3HYy8RuYdoxqrmduEe3midHwvGfxeRD0ztmcPO4uoT4EfxRroCOVbRwD7_OHYShBN_ygwTcRw)


Refer to the second **ParcelEvents** collection and add attributes for the `parcelID`, `status`, and `time`.

![Adding attributes for second collection](https://lh6.googleusercontent.com/9YS6dw-GkYYYAVj39qz714UjkqgdrzoNyfP0tNKtmemeQYSLGRPTy7D8LA2-LFy00694KxbJWXl96-qRqbgy2mVnXYWmOIJjnrKRo8nDKq3K2lhTgRS7s_90Q9hKaDQbAmJ-gwl99PN6xLjyc1MsHeNkIbhVE4xGpfBHRNKHlPNAB4eSbzirrXH-Zg)



### 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:

![Creating an Index](https://lh6.googleusercontent.com/_mR-QXHCYmFU6XYfonRtwNqiomQ-2sl65RuGMeabs6kOLU2Sjl8fmIM6IevGR6vGyDb1xMUJPJT42uzx0B-Z1ML77HIbSXXwNwO7xHFi5HI_uPwJ16-XhwH430q5dhVLfG6biKJgq0Bxyf5rBSJ1vivtdgnMRhCzQLSxhd3899e_HvyRR_HGii_s2Q)



### Setting collection permissions

Navigate to the **Parcels** collection, click the **Settings** tab, and then click the **Add Role** button under **Permissions**:

![Setting role permissions for parcels collection](https://lh3.googleusercontent.com/EdDgRp9lZYCMWYYI-LfLYiel92CwCNVR57kyEayPULYfHIYY2xM11xsmJzCSOPWLZyhG0ltr4zeWDmcwtTPXy_Dl1U_--9phw7hwCbJNcATNl2S-risvgjUxbv0P2UbWKgY5eLPxYz3elhhKY7U2nbZauwA9uZUk6VTsO2kIniEVsuvjq9qWrzoZ8g)


Then, for the role, select the "**any**" option and enable the **Create** and **Read** permissions before clicking **Update**:

![Selecting the roles](https://lh4.googleusercontent.com/H_2BiV7T-tJ83pAqZRc00nHN9ZBI28OvytLLBCwsvj9062NyOyDiQ0D7mexgcUs_BxqCza06lnixGrx7dBROnMp8BE6ovCznWcVJn5bAvy95YCSwClxyGRplT7sbjl9zP3QpeTsogyZLIApyFZG8PtpVA0lNhgCb1My1jtzONPy5xkCKG1KUPR297A)


To set permissions on the **ParcelEvents** collection, go to the **Settings** tab and add the following roles: **Create**, **Read**, **Update**, and **Delete**:

![Setting permission roles for the second ParcelEvents collection](https://lh5.googleusercontent.com/yob1THnIP_3y7XIhstST4fSx2oo99u3uZXZ-KLd5yPqj4GCeoqyKvd_dWStSmarhu2NZuEWShFfLqCqcoyfhahs-R7h4RE0CF6V0-JaxZYu2rLB30ymPa6QrIpqJcZ2aq5dtyK_4WnsGvSMf83nzgQlrOkwhZTNL5k3iPg67Wb7qtUNDPRMyaz_kTA)


Next, you'll use Next.js to begin building the project. 

## Building the project

Refer to the [documentation](https://nextjs.org/docs) 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:


![The project structure for the application](https://paper-attachments.dropboxusercontent.com/s_F4EFCA736B6FFD8AD29B35827934C9DD11CA7ECFC45D607A4AB7FF17C42D461F_1666739788250_Screenshot+2022-10-26+at+00.15.41.png)

### 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:

![Setting the environment variables](https://lh4.googleusercontent.com/LSJuSD988TlYdtzit7rsU85q0Kv38VkeKlIt4RT7Wg-Bd9t3ISY3j4M_0v2kScK0iLHpHm7-Gaq5Rk9UDfYJpDo_Q11XHWeLN4miabmf5h_nUttWGs815M7TTmsBr6kTunwBuP_GI4FkW9pUDS5BpDtsoCnqivCBthgG9ECH8P_bEY4Y8CnQBHua7w)


To obtain your API Endpoint, navigate to the menu and select **Settings**, and copy the URL:

![Obtaining the API endpoint](https://lh6.googleusercontent.com/chmg2VxyJ3vzbraO2kOSCs0iyG39e6pTbTjmxmygR0y79tTeh0g_NiFEu1QcsmqZ3iECsF571l3CTHEVDycmANCOXLhe1nISlatigwvgDVMLe8isXPy-UQGTe3ZPMNKZAzlyVNvhwvYShPRk_GYaCbqlJrUmvsFDn1nYf_-4wJAU6max0l_gndRCJw)


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**:

![Getting the Database ID](https://lh4.googleusercontent.com/W5ft-RlRpk38TDuwAk9PEV0oFNa3ln7hU-9AXbcr3pu1-oXDDM7PQvY--IkLLCyAPxIdGQyEQMxm0Q5FSX_2PCXhvGxZhGq4gWUg8YGXirrDdN--qX-7BbHgbq7tjrkoAROXe-X6JJ-N-fanLk7iwssmyO_wEWbwEHq4cOtZa8lZGFtdGExWkEQswQ)


Next, select the **Parcels** collection on the **Collections** tab, then go to **Settings** and copy your **Collection ID**:

![Getting the Collection ID for the first collection](https://lh6.googleusercontent.com/zEfkaKEbMOlBIhJyMj8uhDJ40aWxQ_hvQlqWl0i7nBOsyTj-rQ7pBUUwCw79T5uDX7sJrzi-8zE-_dYWD4x2cfHF0mgg3dBASreAJg88B-Xx-GjnvrI3TMkwIVMYWUy55qLxByEVeK8c_bWbtUmwz5ycVF-1E-jIsFTVI0YplzAcvEhG6K5vYP5IrQ)


Copy the **Collection ID** for the second **ParcelEvents** collection:

![Getting the Collection ID for the first collection](https://lh5.googleusercontent.com/gUW65WTvWJ_W4wMrB5eadxSKOX-4AYtEJEn_MgLydhqBPW9phG4ly0YIjwM0Y09lGSi6jGBKet6KYk_-O2Bn9Ao2JN6Y4hZjriBiWpb_zps32rvcgoudrV1n1lgrOdmsczaaEko4LpEtnymQ4-xfSR9u72vJjmAA4CKxE2pPg4gRWdHpnUFA0ADaZw)


To obtain the **Project ID**, return to the **Home** page and select **Settings**, then copy the **Project ID**:

![Getting the Project ID](https://lh6.googleusercontent.com/LpJBc8uxu4ig_BIC6WgjiUqZtUIhvRJwfn3GDXc4QcmntFd-3E_rt4WZ3IBsiL024B8ZRyY3oflGSpVVuA32V9BkXOaN1yaAvN8OskByjQ_XUpa3Se3KX5uq-y8WPyy9vJfzb7BVwqxlzhBQjWGbM0GkWsLJG8VxKNqiHmYL_FM1WZvyAtwq0aPvJA)

### Adding Tailwind CSS to the Project

We will use the [Tailwind](https://tailwindcss.com/) 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](https://github.com/debemenitammy/Parcel-Tracker/blob/main/utils/config.js) file in the GitHub repository.

### Creating the landing page

Replace the code in the **pages > index.js** file with this [code](https://github.com/debemenitammy/Parcel-Tracker/blob/main/pages/index.js). You are creating a **functional component** `Home()` in the **index.js** file that does the following:

- Creates `isLoading`, `parcelID`, and `parcel` states.
- Creates a function called `getParcelDetails()` that accepts the parcel ID as a `tracking No` parameter and performs the following operations:
    - The `setLoading()` function initially sets the `isLoading` state to `true` on the calling of the `getParcelDetails()` 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 to `false`.
    - The `setLoading` function will set the `isLoading` state to true once the operation is complete.
    - The condition in the '<main>' 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 the `setParcelID()` function to set the `parcelID` state to the tracking number.
    - When the user clicks the `Track Parcel` link, the `onClick()` event calls the `getParcelDetails()` function with the `parcelID` as a parameter.

### 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](https://github.com/debemenitammy/Parcel-Tracker/blob/main/pages/tracker.js).

This code does the following:

- Creates a `**Tracker()**` functional component, which does the following:
    - Creates a `notifications` state to store the parcel events and a `parcelData` state to store information about the parcel.
- Creates a `getParcelEvents()` function that accepts the `parcelID` as the `tracking 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.
- The `registerSubscriber()` function listens for the real-time events on Appwrite by subscribing to the `documents` events. For every trigger in the `documents` events, the callback calls the `getParcelEvents()` function, passing in the `id` from the `parcelData` state.
- The `useEffect()` monitors the `router.query` and executes a callback which sets the `parcelData` state, calls the `getParcelsEvents()` function, and calls the `registerSubscriber()` function. 

## Testing the project

To test the project, add data to your **Parcels** collection and click **Add Document**:

![Adding document](https://lh4.googleusercontent.com/dBRn_c4--LmxORKIU8z1B09esF4EfJMH1d4Ebp-oYUvnAPg5cDJP6L7iFFqiV-s1vLXut-4AAkkGsQbgHyVYpbgoy4b1OJDqxGyFBf2m0Zlttu1qAVvM4pfclEswBYAMVkN5WZ8eRveUwZSb3iF1oIZ0LltmoXfRo2fk7mAZkOUkMqlwLmystfiViQ)


Then set the following:

![Setting fields in the document](https://lh6.googleusercontent.com/tRCOCqI_nSLJ2j5dVvBS3Y3O36KYbCCcGNOBjnyC11m7T4aRpGSUtfsGA7nWBWXWBj4UL5bONtRajIMRHewuDWUEbuPvPO3p2PHXaGRv6-f39R2hRfaPV66UCSJ-mxN2j4oAOVDDdIaxKeogh01ZzUMnZ4GEweh2LIU-bHTPsobreOpUyf8rI1OkMA)


Afterward, click **Create** and copy the "$id":

![Getting the document ID](https://lh3.googleusercontent.com/fVi0dacdxWFqHyhftucHNlDNRj9VMq6BZZVv0aKpMxsZLzkpB7GgUVujK0HVD2ZNeLZSJsMB2KmpIrAnXgMM7ilGBq8c5kkeB3m_z_xEd72Q6hzH31y2F7mdTH8Ug3DAMgFiJ2OwO9Rc_ITQqGldU7IDFU2niX3SzTZv1JgO09WRWl1hebYKA_VoHQ)


Next, select the **ParcelEvents** collection and create a document using the "$id" you copied:

![Creating a document in the second collection](https://lh3.googleusercontent.com/dKx5Qf7HntvqCxobIusCijSTcA7ojMX_-JLCJa1QDfi4zsBcMgVh41-xhgGWr5zyw8cTV6PpAX5_iHNym7GwsXYhlWzyzfrkOVe4p6_p6ulPO5FTOaqott8H-R2HJspHmglFiHY9QtvI-MO5K0G-c3d4e0blORb5vtAS8h1pjg4JWLig7QzTU2glYg)


Click **Create**, and you should have the following document:

![Viewing the created document](https://lh4.googleusercontent.com/oXxsdrdLgJcEaBVxqV59UHhK7vyuxiPgBuxLu9JtFkklJ1HJk4debatGhMW37HEaU1ICMH2rIZZ7_D2H0RLnTyHMsGprl3WSbWrH0I3hFL4RFg5CW8pMYFxRvKXQZc3Vh4_KUTZ4qahDxd8Ofu5jkKSd_yeEx3gBMYGkCj3WRHEIFlTcqVu6Iw4s2A)


Start the development server for the project by running this command:

```
npm run dev
```

![](https://lh4.googleusercontent.com/tLgWsxVdYPOXj70wA4Q7kitG-0fW0LhGYR3dxA8nZvjRV1Io3mvXIqeJn9KmSEHRcQGbRSxAXRx-H4q3i7iOu8x5dnnRpI0lKY2GKt_M2wu5ACBq8vPw-ku1Xw455dFl8aPcCfmozxEAvM1X8o3YdoE0o9KhU0hHwUpG65NIJR5MXGahYhTpQKqGQw)


Visit the URL "http://localhost:3001" to view the application:

<img width="100%" style="width:100%" src="https://media.giphy.com/media/H1AC2xkS95f8BExSLW/giphy.gif">


# Conclusion

This article demonstrated how to build a real-time parcel tracking service with Next.js and Appwrite.

## Resources 
- [Appwrite Documentation](https://appwrite.io/docs?utm_source=hackmamba&utm_medium=blog&utm_campaign=hackmamba) 
- [Next.js Documentation](https://nextjs.org/docs)