Documentation
Feedback
Guides
VTEX IO Apps

VTEX IO Apps
My Account - StoreV2 version
Official extension
Version: 1.27.1
Latest version: 1.27.1

Notice: React: 3.x | Store: 0.x

Portal

Intro

MyAccount is a canonical app built in all VTEX stores. This app serves as a hub of apps, meaning that it is the entry point for all apps that want to be available for the store's customers.

The app is responsible for handling customer's personal data such as: profile info, passwords, addresses, orders and credit cards. Orders and credit cards are responsibilities of other two apps that come per default with the MyAccount, respectively, these apps are: vtex.my-orders-app and vtex.my-cards.

Features

This app provides a few extension points in order to allow apps to customize stores' experience as needed.

Adding a new page to My Account

First, make sure you have the store-builder as a dependency in you manifest.json:


_10
"builders": {
_10
"messages": "1.x",
_10
"react": "3.x",
_10
+ "store": "0.x"
_10
},

Now, create the file store/interfaces.json and define some interfaces:


_10
{
_10
"my-account-link.my-app-link": {
_10
"component": "MyAppLink"
_10
},
_10
"my-account-page.my-app-page": {
_10
"component": "MyAppPage"
_10
}
_10
}

If you want to block the editing of the document in the my account form, use the props blockDocument


_10
"my-account": {
_10
"props": { "blockDocument": true },
_10
"blocks": [
_10
]
_10
}

Prop nameTypeDescriptionDefault value
blockDocumentbooleanEnables or disables editing the document field in MyAccountundefined

Usage: To block the document field, follow these steps:

  1. In the index.tsx in /react file, the blockDocument property is received from the main store. Pass this property on to AppRouter

_10
<Wrapper>
_10
<div className="vtex-account helvetica flex justify-around">
_10
<AppRouter blockDocument={this.props.blockDocument} />
_10
</div>
_10
</Wrapper>

  1. Pass the property to the ProfileEdit component

_13
component: ComponentClass<void, unknown> | FC
_13
_13
}) => {
_13
return <Route exact key={path} path={path} component={component}/>
_13
}
_13
public render() {
_13
const routes = [
_13
{ path: '/addresses', component: Addresses },
_13
{ path: '/addresses/new', component: AddressCreate },
_13
{ path: '/addresses/edit/:id', component: AddressEdit },
_13
{ path: '/profile', component: Profile },
_13
{ path: '/profile/edit', component: ()=><ProfileEdit blockDocument={this.props.blockDocument}/> },
_13
]

  1. In the ProfileEdit component, pass the property to theProfileFormBox component

_10
const { profile, handleError, blockDocument } = this.props
_10
return (
_10
<ProfileFormBox
_10
profile={profile}
_10
onDataSave={this.handleGoBack}
_10
onError={handleError}
_10
blockDocument={blockDocument}
_10
/>
_10
)
_10
}

  1. In the ProfileFormBox component, pass the property to theProfileContainer component. Just remembering that this component is imported from the vtex.profile-form app

_10
<ProfileContainer
_10
defaultProfile={profile}
_10
onSubmit={this.handleSubmit}
_10
shouldShowExtendedGenders={showGenders}
_10
blockDocument={blockDocument}
_10
>

  1. Follow the steps below in the app ** vtex.profile-form **

The names my-app-link, my-app-page, MyAppLink and MyAppPage may be whatever it makes more sense for you app.

Lastly, create a store/plugins.json file like so:


_10
{
_10
"my-account-menu > my-account-link": "my-account-link.my-app-link",
_10
"my-account-pages > my-account-page": "my-account-page.my-app-page"
_10
}

Creating a my-account-page component

Now create a new file in the root of the "react" folder with the name "MyAppPage.js".


_15
import React, { Fragment } from 'react'
_15
import { Route } from 'vtex.my-account-commons/Router'
_15
// Your component pages
_15
import UserSupport from './components/UserSupport'
_15
import UserPoints from './components/UserPoints'
_15
_15
const MyAppPage = () => (
_15
<Fragment>
_15
{/* This `path` will be added at the end of the URL */}
_15
<Route path="/support" exact component={UserSupport} />
_15
<Route path="/points" exact component={UserPoints} />
_15
</Fragment>
_15
)
_15
_15
export default MyAppPage

In this example you will have two new pages /account/#/support and /account/#/points, rendering the UserSupport and UserPoints components respectively.

Creating a my-account-link component

This component will receive a prop called render. You must call it with an array of objects with the properties name and path. This will create the link given the name and the path provided.

Example of an MyAppLink implementation:


_22
import PropTypes from 'prop-types'
_22
import { intlShape, injectIntl } from 'react-intl'
_22
_22
const MyAppLink = ({ render, intl }) => {
_22
return render([
_22
{
_22
name: intl.formatMessage({ id: 'userPoints.link' }),
_22
path: '/points',
_22
},
_22
{
_22
name: intl.formatMessage({ id: 'userSupport.link' }),
_22
path: '/support',
_22
},
_22
])
_22
}
_22
_22
MyAppLink.propTypes = {
_22
render: PropTypes.func.isRequired,
_22
intl: intlShape.isRequired,
_22
}
_22
_22
export default injectIntl(MyAppLink)

Defining the default home page of My Account

After creating a new page, you can define the default path that will be rendered when the user opens the URL /account/.

  1. Open the Site Editor admin (/admin/cms/site-editor).
  2. Navigate to the My Account page
  3. Click on the "My Account - Home" extension point on the Site Editor's menu
  4. Fill the field "My Account's default path" to the new path

Following the previous examples, we could fill it with "/points", to open the UserPoints page.

Display personal info

Inside the Profile page, right above the edit button, there is another extension point. This one is intended for stores that collect custom data from their customers (such as their hair color or their pet's name). This extension point allows your component to display such information without breaking the page layout.

Usage: Your component shall not render anything: you will simply call the render prop with the appropriate data and it will be displayed together with the user's default information. You should pass in an array of objects containing label and value props. label is the name of the field you which to display (such as Hair color) and value is the value for such field (such as brown). Keep in mind that you must run any necessary preprocessing in your data by yourself before displaying, such as masking or localizing your texts. Also, it is up to you to fetch the data from wherever it is.

Example


_12
const BeautyData = ({ render }) => {
_12
return render([
_12
{
_12
label: 'Hair color',
_12
value: 'Red',
_12
},
_12
{
_12
label: 'Skin color',
_12
value: 'White',
_12
},
_12
])
_12
}

Edit personal info

If you are going to display tailored data inside your customer's profile, you probably want to edit that info too. The last extension point, my-account/profile/input, lets you do that. It will place whatever content you want inside the profile editing form, right above the 'toggle business fields' button, and also use functions provided by you to validate and submit that content.

Usage: Your component may render form components, texts or anything else as desired. We recommend sticking to VTEX's Styleguide or your own design guidelines to avoid breaking the style from the rest of the form. You also receive two props, registerValidator and registerSubmitter. As their names suggest, you must use them to register your validation and submission functions with the main component. You should use componentDidMount to do that. This way, when the user hits 'Submit', your validation function will be called. We then expect you to validate all of your fields and display messages to the user if necessary. If something is invalid, your function should return false in order to halt the submission process, and return true otherwise. The function may either return the boolean value directly or a Promise which will resolve to the appropriate boolean value. When all validation is passed, the form enters submission state. It will now send the default profile information to VTEX's databases and call your submit function so you can do the same. Do not place user interaction or anything related inside that function besides submitting, since the app will return to the display page as soon as all the submitter functions finish executing and anything you display will probably not be noticed by the user.

Example


_52
import React, { Component } from 'react'
_52
import { Input } from 'vtex.styleguide'
_52
_52
class FavColor extends Component {
_52
constructor(props) {
_52
super(props)
_52
this.state = {
_52
color: '',
_52
error: null,
_52
}
_52
}
_52
_52
componentDidMount() {
_52
this.props.registerValidator(this.validate)
_52
this.props.registerSubmitter(this.submit)
_52
}
_52
_52
onChange = e => {
_52
this.setState({ color: e.target.value })
_52
}
_52
_52
validate = () => {
_52
const { color } = this.state
_52
this.setState({ error: null })
_52
if (color !== 'yellow') {
_52
this.setState({ error: 'Your favorite color must be yellow.' })
_52
return false
_52
}
_52
return true
_52
}
_52
_52
submit = () => {
_52
console.log('Success! Your information is saved.')
_52
}
_52
_52
render() {
_52
const { error, color } = this.state
_52
return (
_52
<div className="mb8">
_52
<Input
_52
name="color"
_52
label="Favorite Color"
_52
value={color}
_52
errorMessage={error}
_52
onChange={this.onChange}
_52
/>
_52
</div>
_52
)
_52
}
_52
}
_52
_52
export default FavColor

Author

Gustavo Silva (@akafts) during a Winter Internship of 2018 at VTEX :)

Ft: Felipe Sales (@salesfelipe)

See also
VTEX App Store
VTEX IO Apps