Tutorials

Add a new page

Description

In this example we are going to add a new page to the project, and will go through each individual steps for this process. Here we are creating a page for Register Page. Which will have a form to list contact details, form for address details and a submit button.

We will create the page itself first and add components.

Step 1: Create the index file for the page

  1. Go to ~/pages folder and create a new folder named register.
  2. In this folder i.e, ~pages/register add a vue file name index.vue

Now we will make page to be accessible form <base-url>/register

Add the following code

<template>
  <div class="content-container md:my-6">
    <h3 class="header-text">
      Create My Account  <!--@todo: add this to translation -->
    </h3>

    <Panel>
      <!-- Add components Here -->
    </Panel>
  </div>
</template>

<script>
import Vue from "vue";
import Panel from "~/components/UI/panel/Panel.vue";

export default Vue.extend({
  name: "RegisterPage",
  components: {Panel}
});
</script>

NOTES:

  • All strings, texts, labels etc., will be rendered from the translation files we will add these to all translations files upcoming steos. But uptill then it is a good habit to mark them for todo.
  • We have also imported the Panel component from ~/components/UI folder

Create Component files

This project heavily emphasises Single Responsibility Principle for it's component so you should always keep in mind that if a page can be divided into multiple individual components we should. And each component should idealy handle only one responsiblity.

Like in our case we will create two components for Contact details and for Address details.

Add ContactDetails Component

Create a component named ContactDetails.vue in ~/components/resister folder.

<template>
  <div>
    <h1 class="header-text-2">Contact Details</h1> <!--@todo: Add strings to translations -->

    <form action="" method="post" class="mt-8 flex flex-col gap-6">
      <div class="w-3/4 md:w-1/4">
        <client-only>
          <form-label class="gap-2">
            <strong class="text-size-2 text-blue">Title*</strong>  <!--@todo: Add strings to translations -->
            <form-select
              v-model="form.title"
              :options="getTitleOptions()"
              required
            >
              <template #first
                ><option disabled selected>Select Title</option>  <!--@todo: Add strings to translations -->
              </template>
            </form-select>
          </form-label>
        </client-only>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue"
            >{{ $tc("register.labels.firstName") }}*</strong
          >
          <form-input v-model="form.firstName" type="text" required />
        </form-label>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue"
            >{{ $tc("register.labels.lastName") }}*</strong
          >
          <form-input v-model="form.lastName" type="text" required />
        </form-label>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue">{{
            $tc("register.labels.company")
          }}</strong>
          <form-input v-model="form.company" type="text" required />
        </form-label>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue"
            >{{ $tc("register.labels.email") }}*</strong
          >
          <form-input v-model="form.email" type="text" required />
        </form-label>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue">{{
            $tc("register.labels.landline")
          }}</strong>
          <form-input v-model="form.landline" type="text" required />
        </form-label>
      </div>

      <div class="w-1/2 md:w-1/2">
        <form-label class="gap-2">
          <strong class="text-size-2 text-blue"
            >{{ $tc("register.labels.mobile") }}*</strong
          >
          <form-input v-model="form.mobile" type="text" required />
        </form-label>
      </div>
    </form>
  </div>
</template>

<script lang="ts">
  // ...
</script>

Import UI components

If there are components that alredy exists in the ~/components folder. We should use them. Particularly the UI related components are already created in ~/components/UI folder. Here we are importing FormLabel and FormInput components.

add the following in script tag.

import Vue from "vue";
import FormLabel from "~/components/UI/forms/FormLabel.vue";
import FormSelect from "~/components/UI/forms/FormSelect.vue";
import FormInput from "~/components/UI/forms/FormInput.vue";

export default Vue.extend({
    name: "ContactDetails",
    components: { FormInput, FormSelect, FormLabel },
    data() {
        return {
            form: {
                title: "",
                firstName: "",
                lastName: "",
                landline: "",
                mobile: "",
                company: "",
                email: "",
            },
        };
    },
    methods: {
        getTitleOptions() {
            // @todo: update options
            return [
                {
                    value: "Mr",
                    text: "Mr",
                },
                {
                    value: "Mrs",
                    text: "Mrs",
                },
            ];
        },
    },
});

Add AddressDetails component

Add AddressDetails.vue file in ~/components/register/ folder.

<template>
  <div>
    <div class="w-1/2 md:w-1/2">
      <form-label class="gap-2">
        <strong class="text-size-2 text-blue"
          >{{ $tc("register.labels.address") }}*</strong
        >
        <form-input v-model="address" type="text" required />
      </form-label>
    </div>

    <p class="text-size-4 font-bold text-blue">
      {{ $tc("register.addressDetailsNote") }}
    </p>
  </div>
</template>

<script lang="ts">
  //...
</script>

####Add the following in script tag

import Vue from "vue";
import FormLabel from "~/components/UI/forms/FormLabel.vue";
import FormInput from "~/components/UI/forms/FormInput.vue";

export default Vue.extend({
  name: "AddressDetails",
  components: { FormInput, FormLabel },
  data() {
    return {
      address: "",
    };
  },
});

Step 3: Add the components to the main page

In ~/pages/resgister/index.vue add the above made components and also include DefaultButton component from the UI folder for submit button.

<template>
  <div class="content-container md:my-6">
    <h3 class="header-text">
      {{ $tc("login.createAccount") }}
    </h3>

    <Panel>
      <ContactDetails />
      <HorizontalSeparator />

      <AddressDetails />
      <HorizontalSeparator />
      
      <DefaultButton @clickAction="register"> Continue </DefaultButton>
    </Panel>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Panel from "~/components/UI/panel/Panel.vue";
import ContactDetails from "~/components/register/ContactDetails.vue";
import DefaultButton from "~/components/UI/button/DefaultButton.vue";
import HorizontalSeparator from "~/components/UI/separators/HorizontalSeparator.vue";
import AddressDetails from "~/components/register/AddressDetails.vue";

export default Vue.extend({
  name: "RegisterPage",
  components: {
    AddressDetails,
    HorizontalSeparator,
    DefaultButton,
    ContactDetails,
    Panel,
  },
  data() {
    return {};
  },
  methods: {
    register(event: any) {
      //... @todo: write code here
    },
  },
});
</script>

Step 4: Update UI using Tailwind.css

Now that we have the basic structure you can update the UI using tailwind classes to make it match the exact design given by the client.

Step 5: Add translation files

Now that we have the basic UI and interface setup we can add the strings used to the translation files

  1. Go to ~/utils/translations/data/UK-EN.json file
  2. Include the following properties at the end.
    "register": {
        "createAccount": "Create my account",
        "contactDetails": "Contact Details",
        "labels": {
          "title": "Title",
          "firstName": "First Name",
          "lastName": "Last Name",
          "landline": "Landline",
          "mobile": "Mobile",
          "company": "Company",
          "email": "E-mail",
          "address": "Your Address",
          "password": "Password",
          "confirmPassword": "Confirm Passoword"
        },
        "placeholder": {
          "title": "Select"
        },
      }
    
  3. In the vue files for components and page replace the stings with appropriate strings For example, to update the header text in the page
    <h3 class="header-text">
      {{ $tc("register.createAccount") }}
    </h3>
    
    Similarly, for updating labels in component files use
    <strong class="text-size-2 text-blue">
      {{ $tc("register.labels.firstName") }}*
    </strong>
    
  4. Important: Update all other translation files for all other regions specifed in ~/utils/translations/data/ folder. In case you do not know translation for any specific region, you can paste the same translation as that in UK-en.json.

Step 6: Add API layer

  1. Take reference for Toolstation API Documenttion here. If you don't have access please check Team's Project Credentials page or contact your reporting manager.
  2. Add account.api.ts file in ~services/api folder.
import { NuxtAxiosInstance } from "@nuxtjs/axios";
import { AxiosResponse } from "axios";

const ENDPOINTS = {
ACCOUNT: (accountId: string) => `/accounts/${accountId}`,
ACCOUNT_CUSTOMERS: (accountId: string) => `/accounts/${accountId}/customers`,
ACCOUNT_CUSTOMER: (accountId: string, customerId: string) =>
`/accounts/${accountId}/customers/${customerId}`,
ACCOUNT_ORDERS: (accountId: string) => `/accounts/${accountId}/orders`,
};

export const getAccount = async (
$axios: NuxtAxiosInstance,
accountId: string
): Promise<AxiosResponse<any>> =>
await $axios.$get(ENDPOINTS.ACCOUNT(accountId));

export const getAccountCustomers = async (
$axios: NuxtAxiosInstance,
accountId: string
): Promise<AxiosResponse<any>> =>
await $axios.$get(ENDPOINTS.ACCOUNT_CUSTOMERS(accountId));

export const createAccountCustomer = async (
$axios: NuxtAxiosInstance,
accountId: string,
data: any
): Promise<AxiosResponse<any>> =>
await $axios.$post(ENDPOINTS.ACCOUNT_CUSTOMERS(accountId), data);

export const deleteAccountCustomer = async (
$axios: NuxtAxiosInstance,
accountId: string,
customerId: string
): Promise<AxiosResponse<any>> =>
await $axios.$delete(ENDPOINTS.ACCOUNT_CUSTOMER(accountId, customerId));

Step 7: Add Service layer

Add the account.services.ts in ~/services folder.

// TODO

Step 8: Update register button

Step 9: Update Types

Step 10: Update Store

Step 11: Add Unit Test files for components

Step 12: Things to keep in mind


Copyright © 2026