The stats revealed that adding personalization may increase sales by an average of 19% across the board, and there is no need to prove that consumers' birthdays are one of the most personal and pleasantly surprising ways to show them that you care. Having said that, I will show you how to add the "Date of birth" field to the customer profile on Vue Storefront. With it, your company will gain the foundation for marketing campaigns, not only birthday-based. The tutorial is quite universal, so developers can use it to add any other fields.

This tutorial will show you how to apply this feature in Vue Storefront 1.12.2 with VSF-API & Magento 2 on Backend. I will show you examples both for Default 1.12.1 and Capybara theme 1.0.2.

Let’s start!

What is the attribute name for the “Date of birth” in Magento 2?

To discover this - you have to open Magento 2 REST API Swagger Documentation. Under this link you should find the Customer data model: 

Internally, in VSF-API we are using this exact endpoint (PUT /V1/customers/me). 

As you can see - we have a field called dob - which is an abbreviation for the date of birth. If you want, you could add support for any other field based on the data model.

At first, go to src/modules and create a vsf-date-of-birth directory, inside create index.ts file with that content:

src/modules/vsf-date-of-birth/index.ts

import { USER_INFO_LOADED } from '@vue-storefront/core/modules/user/store/mutation-types';
import { StorefrontModule } from '@vue-storefront/core/lib/modules';
import { extendStore } from '@vue-storefront/core/helpers';
const mutations = {
  [USER_INFO_LOADED] (state, currentUser) {
    state.current = currentUser
        ? {
            ...currentUser,
            ...(!('dob' in currentUser) ? { dob: '' } : {})
        }
        : currentUser;
  }
}
const userModule = {
  mutations
}
export const ExtendedUser: StorefrontModule = function () {
  extendStore('user', userModule);
}

As you can see - I am overriding one mutation from the user's module. I am adding the dob field to the user's object as MyProfile.vue component will build its own state based on this.$store.state.user.current - thanks to this change, inside we will have a reactive dob field in case it does not exist by default!

You might wonder why I’ve used this ternary operator. currentUser field would have a null value after logout by default - without “else part” (after the colon), it would be equal {} instead of null. It would break conditions in themes.

In the next step, you have to add a new module to the src/modules/client.ts file. Open it, at the top add import:

src/modules/client.ts

import { ExtendedUser } from './vsf-date-of-birth';

Inside registerClientModules call registerModule method with imported object:

src/modules/client.ts

export function registerClientModules () {
 // ...
 registerModule(ExtendedUser)
 // ...
}

Then we will customize the in-theme part.

Setting birthday in VSF default theme

Open:

src/themes/vsf-default/components/core/blocks/MyAccount/MyProfile.vue

and inside methods paste:

src/themes/vsf-default/components/core/blocks/MyAccount/MyProfile.vue

exitSection (event, updatedProfile) {
  this.$bus.$emit('myAccount-before-updateUser', {
    ...updatedProfile,
    dob: this.currentUser.dob
  })
  if (!updatedProfile) {
    this.currentUser = Object.assign({}, this.$store.state.user.current)
    this.userCompany = this.getUserCompany()
    this.changePassword = false
    this.oldPassword = ''
    this.password = ''
    this.rPassword = ''
    if (!this.userCompany.company) {
      this.addCompany = false
    }
    this.remainInEditMode = false
  }
  if (!this.remainInEditMode) {
    this.isEdited = false
  }
 }

The only difference between this and the original one is this additional line:

this.$bus.$emit('myAccount-before-updateUser', {
  ...updatedProfile,
  dob: this.currentUser.dob
})

I just added the dob field to the object in the second argument. So it will be sent to the backend in the request

After that, we should create a custom validator. The value should be filled in according to the YYYY-MM-DD. So in validations, add (remember to add , after email object):

src/themes/vsf-default/components/core/blocks/MyAccount/MyProfile.vue

dob: {
    matchesDatePattern: value => !value ||
/^[0-9]{4}-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])$/.test(value)
}

Then we have to add new field in the template, so below:

src/themes/vsf-default/components/core/blocks/MyAccount/MyProfile.vue

<base-input
  class="col-xs-12 col-md-6 mb10"
  type="email"
  name="email-address"
  autocomplete="email"
  placeholder="$t('Email address')"
  v-model="currentUser.email"
  :validations="[
    {
      condition: !$v.currentUser.email.required,
      text: $t('Field is required')
    },
    {
      condition: !$v.currentUser.email.email,
      text: $t('Please provide valid e-mail address.')
    }
  ]"
/>

Add (of course you could add this in other place in this component - but this is suggested by me and fits perfect):

src/themes/vsf-default/components/core/blocks/MyAccount/MyProfile.vue

<base-input
  class="col-xs-12 col-md-6 mb10"
  type="text"
  name="bday"
  autocomplete="bday"
  :placeholder="$t('Date of birth')"
  v-model.trim="currentUser.dob"
  :validations="[
    {
      condition: !$v.currentUser.dob.matchesDatePattern,
      text: $t('Field should match pattern YYYY-MM-DD')
    }
  ]"
/>

As you can see, we requested the new translation "Your date of birth" and "Field should match pattern YYYY-MM-DD". We should add it to the languages that we are interested in. Open .csv, which you use in your theme's directory resource/i18n. (For me, it could be pl-PL.csv.)

At the bottom, add lines:

src/themes/vsf-default/resource/i18n/pl-PL.csv

"Date of birth","Data urodzenia"
"Field should match pattern YYYY-MM-DD","Wartość pola powinna być uzupełniona według następującego schematu: RRRR-MM-DD"

The left one is an identifier sent to the $t method, and the right one is a translation in the current language.

Setting a birthday date in Capybara theme

Caution: Please make sure you have applied this PR in your Capybara’s code.

Open:

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue and inside data, add:

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

dob: ''

Inside methods find updatePersonalData. Below:

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

updatedProfile.email = this.email

Paste:
src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue

updatedProfile.dob = this.dob

OK, we have logic for sending dob. Now, we should create logic for properly loading dob to the component's data. For that purpose, inside beforeMount below:

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

this.email = currentUser.email;

Add this:
src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue

this.dob = currentUser.dob;

Then, we should create a custom validator. The value should be filled according to pattern YYYY-MM-DD or just let an empty string. So in validations add dob object:

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

validations: {
   // ...
   dob: {
     matchesDatePattern: value => !value ||
/^[0-9]{4}-(1[0-2]|0[1-9])-(3[01]|[12][0-9]|0[1-9])$/.test(value)
   }
}

Then, we have to add the new field in the template, so below:
src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

<SfInput
  v-model="email"
  type="email"
  name="email"
  :label="$t('Your e-mail')"
  required
  :valid="!$v.email.$error"
  :error-message="
    !$v.email.required
       ? $t('Field is required.')
       : $t('Please provide valid e-mail address.')
  "
  class="form__element"
/>

Add (of course you could add this in other place in this component - but this is suggested by me and fits perfect):

src/themes/vsf-capybara/components/molecules/m-update-personal-data.vue 

<SfInput
  v-model="dob"
  type="dob"
  name="bday"
  autocomplete="bday"
  :label="$t('Your date of birth')"
  :valid="!$v.dob.$invalid"
  :error-message="$t('Field should match pattern YYYY-MM-DD')"
  class="form__element"
/>

As you can see, we requested the new translation “Your date of birth” and “Field should match pattern YYYY-MM-DD”. We should add it to the languages that we are interested in. Open .csv which you use in your theme’s resource/i18n directory. For me, it could be pl-PL.csv. At the bottom add lines like:

src/themes/vsf-capybara/resource/i18n/pl-PL.csv

"Your date of birth","Data urodzenia"
"Field should match pattern YYYY-MM-DD","Wartość pola powinna być uzupełniona według następującego schematu: RRRR-MM-DD"

The left one is an identifier sent to the $t method, and the right one is a translation in the current language.

Changes in VSF-API

Open src/models/userProfileUpdate.schema.extension and put there:

src/models/userProfileUpdate.schema.extension.json

{
   "properties": {
       "customer": {
           "properties": {
               "dob": {
                   "type": "string"
               }
           }
       }
   }
}

It will only check for type. We cannot check the pattern here because it would not support - empty string value for removing dob.

That's all. 

Restart your VSF-API and VSF-PWA - now, you should be able to save the date of birth in MyAccount's view!

You have just made your marketing department happy because it is equipped now with additional data ready to use in the next campaigns and satisfy customers surprised when additional discount appears on their birthday. Now you can sit down with a cup of coffee and think what other interesting fields can appear in your eCommerce app that uses Vue Storefront.