Building an Order Tracking Bar for E-Commerce: A Step-by-Step Guide in Next.js

Photo by Andrew Neel on Unsplash

Building an Order Tracking Bar for E-Commerce: A Step-by-Step Guide in Next.js

Introduction

In the fast-paced world of e-commerce, tracking the status of orders is crucial for both businesses and customers. A well-designed order tracking system enhances the user experience and keeps customers informed about the whereabouts of their purchases. In this tutorial, we'll walk you through the process of creating an ordered item tracking bar in a Next application.

We'll be using Next, a popular React-based framework for building user interfaces, to implement the order tracking bar. Let's break down the process step-by-step.

Prerequisites

Before diving into the code, let's ensure you have the necessary tools and knowledge:

  • Node.js and npm: Install Node.js and npm, essential for running JavaScript applications.

  • Next.js: Set up Next.js using Create Next App or your preferred method.

  • Styled Components: Install styled components to add style to our Next.js components.

  • Moment.js: Install Moment.js to format dates for a better user experience.

  • Basic React Knowledge: Familiarity with React will be beneficial.

  • Code Editor: Choose a code editor of your preference (e.g., Visual Studio Code).

Step 1: Setting up the Next Application

To get started, let's set up a new React application using Next.js, a framework that enables server-side rendering and other features to streamline the development process.

npx create-next-app order-tracking-bar
cd order-tracking-bar
npm start

This will create a new project and start the development server.

// package.json

{
  "name": "track-order-bar",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    // ... other dependencies
    "moment": "^2.29.4",
    // ... other dependencies
    "styled-components": "^6.0.8",
    "typescript": "5.2.2"
  }
}

Step 2: Creating the Order Tracking Components

We'll start by defining the components needed for our order tracking bar. The Step component will represent each step in the order tracking process and the IconCheckBlue component will display a blue checkmark icon.

//app/IconCheckBlue.tsx
import React from "react";

// ... SVG markup for the blue checkmark icon
export default function IconCheckBlue() {
  return (
    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
      <path className="icon" fill-rule="evenodd" clip-rule="evenodd" d="M8.99999 16.2008C10.9095 16.2008 12.7409 15.4422 14.0912 14.092C15.4414 12.7417 16.2 10.9103 16.2 9.00078C16.2 7.09122 15.4414 5.25987 14.0912 3.90961C12.7409 2.55935 10.9095 1.80078 8.99999 1.80078C7.09043 1.80078 5.25908 2.55935 3.90882 3.90961C2.55856 5.25987 1.79999 7.09122 1.79999 9.00078C1.79999 10.9103 2.55856 12.7417 3.90882 14.092C5.25908 15.4422 7.09043 16.2008 8.99999 16.2008ZM12.3363 7.83708C12.5002 7.66734 12.5909 7.44 12.5889 7.20402C12.5868 6.96804 12.4922 6.74231 12.3253 6.57544C12.1585 6.40858 11.9327 6.31393 11.6967 6.31187C11.4608 6.30982 11.2334 6.40054 11.0637 6.56448L8.09999 9.52818L6.93629 8.36448C6.76655 8.20054 6.5392 8.10982 6.30323 8.11188C6.06725 8.11393 5.84152 8.20858 5.67465 8.37544C5.50778 8.54231 5.41313 8.76804 5.41108 9.00402C5.40903 9.24 5.49975 9.46734 5.66369 9.63708L7.46369 11.4371C7.63246 11.6058 7.86134 11.7006 8.09999 11.7006C8.33864 11.7006 8.56751 11.6058 8.73629 11.4371L12.3363 7.83708Z" fill="#D8DDE0"/>
    </svg>
  );
}
// app/page.tsx

// ... other imports

export default function Home() {
  return (
    <>
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "" },
            { orderStatusID: 3, createdDate: "" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 1,
        }}
      />
      {/* ... Steps for other order statuses */}
    </>
  );
}

Step 3: Styling the Order Tracking Bar

Let's style the order tracking bar to make it visually appealing and easy to use. We'll define the styles using styled-components, a CSS-in-JS library.

import styled from "styled-components";
import globalStyles from "./globalStyles";

//css styles for the order tracking bar
export const StepperStyle = styled.section`
  .step-wrap {
    max-width: 100%;
    width: 100%;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    padding-top: 24px;
    border-top: 1px solid ${globalStyles?.colors?.border3Color};
    li {
      width: 100%;
      display: flex;
      position: relative;
      margin-bottom: 35px;
      color: ${globalStyles?.colors?.stepColor};
      &:after {
        position: absolute;
        left: 8px;
        top: 22px;
        content: "";
        width: 1px;
        height: 60px;
        background-color: ${globalStyles?.colors?.border3Color};
      }
      &:last-child {
        margin-bottom: 0;
        &:after {
          display: none;
        }
      }
      svg {
        margin-top: 2px;
      }
      .step_title {
        font-size: 16px;
      }
      .step_date {
        font-size: 14px;
      }
      &.active,
      .completed {
        color: ${globalStyles?.colors?.blueColor};
        .step_title {
          font-weight: 700;
        }
        .icon {
          fill: ${globalStyles?.colors?.blueColor};
        }
      }
    }
    @media all and (min-width: 1025px) {
      display: flex;
      justify-content: space-between;
      padding-bottom: 24px;
      border-top: none;
      border-bottom: 1px solid ${globalStyles?.colors?.border3Color};
      .step {
        width: auto;
        margin-bottom: 0;
        background-color: ${globalStyles?.colors?.whiteColor};
        z-index: 4;
        padding: 0 15px;
        &:after {
          position: absolute;
          left: 100%;
          top: 10px;
          content: "";
          width: 400px;
          height: 1px;
          background-color: ${globalStyles?.colors?.border3Color};
          z-index: -1;
        }
        &.completed {
          &:before {
            content: "";
            position: absolute;
            left: 24px;
            top: calc(100% + 16px);
            transform: translateX(-50%);
            width: 0;
            height: 0;
            border-left: 6px solid transparent;
            border-right: 6px solid transparent;
            border-bottom: 8px solid ${globalStyles?.colors?.blueColor};
          }
        }
      }
    }
  }
`;

Step 4: Implementing Order Status Logic

We'll implement the logic to determine the status of each order and apply the appropriate styles to the order tracking steps based on the status.

// app/page.tsx

function Step({ productItem }: any) {
  // ... other logic for determining order status and applying styles
}

Step 5: Displaying Order Tracking Information

Finally, let's display the order tracking information for each step, including the order status and relevant dates.

// app/page.tsx
// ... other imports

function Step({ productItem }: any) {
  return (
    <StepperStyle className="stepper">
      <ul className="step-wrap">
        {/* ... HTML markup for each step displaying order tracking information */}
      </ul>
    </StepperStyle>
  );
}

export default function Home() {
  return (
    <>
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "" },
            { orderStatusID: 3, createdDate: "" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 1,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 2,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "03-26-2023" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 3,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "03-26-2023" },
            { orderStatusID: 4, createdDate: "03-27-2023" },
          ],
          orderStatusId: 4,
        }}
      />
    </>
  );
}

This is the final code for rendering steps for order tracking based on orderStatusId

"use client";
import { useEffect, useState } from "react";
import { StepperStyle } from "./style";
import IconCheckBlue from "./IconCheckBlue";
import moment from "moment";

/**
 *
 * @param {*} inputDate
 * @param {*} dateFormat
 * @returns
 */
export const getFormattedDate = (inputDate: any, dateFormat = "DD MMM, YY") => {
  return !!inputDate ? moment(inputDate).format(dateFormat) : "";
};

const STATUS_ACTIVE_CLASSES = {
  CONFIRMED: "",
  SHIPPED: "",
  OUT_FOR_DELIVERY: "",
  DELIVERED: "",
};

export const ORDER_API_KEYS = {
  ORDERED_STATUS_ID_KEY: "orderStatusId",
};

export const ORDER_STATUSES_ID = {
  CONFIRMED: 1,
  SHIPPED: 2,
  OUT_FOR_DELIVERY: 3,
  DELIEVERED: 4,
  CANCELLED: 5,
  DEFAULT: 7,
  RETURNED: 8,
};

export const ORDER_STATUSES = {
  [ORDER_STATUSES_ID["CONFIRMED"]]: {
    orderStatusId: ORDER_STATUSES_ID["CONFIRMED"],
    label: "Order Confirmed",
  },
  [ORDER_STATUSES_ID["SHIPPED"]]: {
    orderStatusId: ORDER_STATUSES_ID["SHIPPED"],
    label: "Shipped ",
  },
  [ORDER_STATUSES_ID["OUT_FOR_DELIVERY"]]: {
    orderStatusId: ORDER_STATUSES_ID["OUT_FOR_DELIVERY"],
    label: "Out for Delivery ",
  },
  [ORDER_STATUSES_ID["DELIEVERED"]]: {
    orderStatusId: ORDER_STATUSES_ID["DELIEVERED"],
    label: "Delivered",
  },
  [ORDER_STATUSES_ID["CANCELLED"]]: {
    orderStatusId: ORDER_STATUSES_ID["CANCELLED"],
    label: "Order Cancelled",
  },
  [ORDER_STATUSES_ID["DEFAULT"]]: {
    orderStatusId: ORDER_STATUSES_ID["DEFAULT"],
    label: "Default",
  },
  [ORDER_STATUSES_ID["RETURNED"]]: {
    orderStatusId: ORDER_STATUSES_ID["RETURNED"],
    label: "Returned",
  },
};

function Step({ productItem }: any) {
  const [statusClass, setStatusClass] = useState(STATUS_ACTIVE_CLASSES);

  useEffect(() => {
    switch (productItem?.[ORDER_API_KEYS["ORDERED_STATUS_ID_KEY"]]) {
      case ORDER_STATUSES_ID["CONFIRMED"]:
        return setStatusClass({
          CONFIRMED: "active completed",
          SHIPPED: "",
          OUT_FOR_DELIVERY: "",
          DELIVERED: "",
        });
      case ORDER_STATUSES_ID["SHIPPED"]:
        return setStatusClass({
          CONFIRMED: "active",
          SHIPPED: "active completed",
          OUT_FOR_DELIVERY: "",
          DELIVERED: "",
        });
      case ORDER_STATUSES_ID["OUT_FOR_DELIVERY"]:
        return setStatusClass({
          CONFIRMED: "active",
          SHIPPED: "active",
          OUT_FOR_DELIVERY: "active completed",
          DELIVERED: "",
        });
      case ORDER_STATUSES_ID["DELIEVERED"]:
        return setStatusClass({
          CONFIRMED: "active",
          SHIPPED: "active",
          OUT_FOR_DELIVERY: "active",
          DELIVERED: "active completed",
        });
    }
  }, []);

  const getDeliveryStatusDate = (statusId: any) => {
    if (
      Array.isArray(productItem?.deliveryStatus) &&
      !!productItem?.deliveryStatus?.length
    ) {
      for (let val of productItem?.deliveryStatus) {
        if (val?.orderStatusID === statusId) {
          return getFormattedDate(val?.createdDate);
        }
      }
    }
    return "";
  };

  return (
    <StepperStyle className="stepper">
      <ul className="step-wrap">
        <li className={`step ${statusClass["CONFIRMED"]}`}>
          <span className="round-tab mr-5">
            <IconCheckBlue />
          </span>
          <div className="step-text">
            <div className="step_title">
              {ORDER_STATUSES[ORDER_STATUSES_ID["CONFIRMED"]]["label"]}
            </div>
            <div className="step_date">
              {getDeliveryStatusDate(ORDER_STATUSES_ID["CONFIRMED"])}
            </div>
          </div>
        </li>
        <li className={`step ${statusClass["SHIPPED"]}`}>
          <span className="round-tab mr-5">
            <IconCheckBlue />
          </span>
          <div className="step-text">
            <div className="step_title">
              {ORDER_STATUSES[ORDER_STATUSES_ID["SHIPPED"]]["label"]}
            </div>
            <div className="step_date">
              {getDeliveryStatusDate(ORDER_STATUSES_ID["SHIPPED"])}
            </div>
          </div>
        </li>
        <li className={`step ${statusClass["OUT_FOR_DELIVERY"]}`}>
          <span className="round-tab mr-5">
            <IconCheckBlue />
          </span>
          <div className="step-text">
            <div className="step_title">
              {ORDER_STATUSES[ORDER_STATUSES_ID["OUT_FOR_DELIVERY"]]["label"]}
            </div>
            <div className="step_date">
              {getDeliveryStatusDate(ORDER_STATUSES_ID["OUT_FOR_DELIVERY"])}
            </div>
          </div>
        </li>
        <li className={`step ${statusClass["DELIVERED"]}`}>
          <span className="round-tab mr-5">
            <IconCheckBlue />
          </span>
          <div className="step-text">
            <div className="step_title">
              {ORDER_STATUSES[ORDER_STATUSES_ID["DELIEVERED"]]["label"]}
            </div>
            <div className="step_date">
              {getDeliveryStatusDate(ORDER_STATUSES_ID["DELIEVERED"])}
            </div>
          </div>
        </li>
      </ul>
    </StepperStyle>
  );
}

export default function Home() {
  return (
    <>
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "" },
            { orderStatusID: 3, createdDate: "" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 1,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 2,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "03-26-2023" },
            { orderStatusID: 4, createdDate: "" },
          ],
          orderStatusId: 3,
        }}
      />
      <Step
        productItem={{
          deliveryStatus: [
            { orderStatusID: 1, createdDate: "03-23-2023" },
            { orderStatusID: 2, createdDate: "03-25-2023" },
            { orderStatusID: 3, createdDate: "03-26-2023" },
            { orderStatusID: 4, createdDate: "03-27-2023" },
          ],
          orderStatusId: 4,
        }}
      />
    </>
  );
}

Conclusion

Congratulations! You've successfully built an order tracking bar for an e-commerce application using Next. This tracking bar enhances the user experience by providing real-time updates on the status of orders, ultimately improving customer satisfaction.

Feel free to further customize and enhance this order tracking bar to suit your specific project requirements.

Happy coding!