Giter Club home page Giter Club logo

store-block's Introduction

Store Block course template

Here you'll learn how to create awesome Store Framework blocks!

store-block's People

Contributors

vtexgithubbot avatar

Watchers

Vincenzo Mario Conte avatar

store-block's Issues

Creating the countdown block feature

Creating the countdown block feature

Introduction

Now we covered the component's basics, it's time to implement the countdown effectively. For that, we need to use a React hook called useState.

The useState hook

It is called within the functional component to update and consume the component state. The state represents the component's current state.

The useState returns a pair: the current state value and a function to update it.

Seeing the example provided on the previous step we can understand these concepts:

const [count, setCount] = useState(0)

In the above code piece, you might observe three things:

  • In the count variables, it's possible to get the current state;
  • setCount is a function used for updating it;
  • 0 is its initial state;
const [timeRemaining, setTime] = useState<TimeSplit>({
  hours: '00', 
  minutes: '00', 
  seconds: '00'
})

Activity

  1. First, we need to import a few functions and types to continue. Inside the Countdown component, import the following:

    //react/Countdown.tsx
    import React, { useState } from 'react'
    import { TimeSplit } from './typings/global'
    import { tick, getTwoDaysFromNow } from './utils/time'

    The getTwoDaysFromNow function will be used to deal with edge cases. It'll be explained later on in this step.

  2. Next step is to add the state update hook (useState):

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate }) => {
    +   const [timeRemaining, setTime] = useState<TimeSplit>({
    +     hours: '00',
    +     minutes: '00',
    +     seconds: '00'
    +   })
    
        return (
          <div>
            { targetDate }
          </div>
        ) 
    }
  3. After doing that, we'll add a default constant targetDate for the edge case where the prop is not defined. We'll use as fallback a date that is defined as two days from the current date, this date is calculated on an util function that was previously imported from the /utils folder.

    //react/Countdown.tsx
    const DEFAULT_TARGET_DATE = getTwoDaysFromNow()
  4. Now, we need to add the tick function and the DEFAULT_TARGET_DATE constant to make the countdown work:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
    })
    
    + tick(targetDate, setTime)
    
      return (
        <div>
          { targetDate }
        </div>
      ) 
    }
  5. At last but not least, change the h1 so that it shows the countdown that we've created. For that, we need to use the timeRemaining current state:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
      tick(targetDate, setTime)
    
      return (
        <div>   
    -     <h1>{ targetDate }</h1>
    +     <h1>{ `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` }</h1>
        </div>
      ) 
    }

    The countdown string formatting is in a HH:MM:SS format, made through an hours, minutes and seconds splitting.

Therefore, with these changes, we'll see a real-time update of the countdown! The result on the homepage is this:

image

Internationalization practices in VTEX IO

Internationalization practices in VTEX IO

Introduction

With the customized block in the store, we need to learn to internationalize the content presented.

It is important to remember that blocks must always follow good localization practices, and must not show hardcoded strings, but ones that are sensitive to the language that the store operates.

Don't worry, you won't need to add translations of all texts for the various languages in which the Store Framework is used. Therefore, in this stage, will be presented concepts about the internationalization of apps and how to do it.

The Messages

The concept of messages makes it easy to add new languages ​​to the theme. The Messages centralize all translation services on the platform. Given a text to be translated, Messages will first check the user-defined context, then check the translations of the apps and, finally, go through the automatic translation system.

In the directory structure, you can see that there is a folder called messages, which has three main files: pt.json, en.json andes.json, each responsible for the translations: Portuguese, English and Spanish, respectively. In addition, in order to provide better automatic translations, the context.json file is used, which is responsible for avoiding ambiguities.

To use such definitions, the translation files mentioned above are JSON, whose keys are messages and values ​​are translations.

The context.json file is necessary and must contain all messages, besides offering automatic translations in exceptional cases.

Activity

You must have learned how to use our builder messages, and it will be through it that internationalized strings will be added to the components.

  1. To do so, in the directory /messages, add now a message for the title of the component:

    messages/pt.json

    {
      ...,
    +	"countdown.title": "Contagem Regressiva"
    }

    messages/en.json

    {
      ...,
    +	"countdown.title": "Countdown"
    }

    messages/es.json

    {
      ...,
    +	"countdown.title": "Cuenta Regresiva"
    }

    messages/context.json

    {
      ...,
    +	"countdown.title": "Countdown"
    }
  2. After that, to render the title the component FormattedMessage of the lib react-intl must be used.

    The lib react-intl supports many ways of configuration and internationalization, it is worth checking it out.

  3. Add the lib using yarn add react-intl in the react directory

  4. In your component's code, Countdown.tsx, import the FormattedMessage

    //react/Countdown.tsx
    import { FormattedMessage } from 'react-intl'
  5. Add a new prop to the interface CountdownProps:

    interface CountdownProps {
    + title: string
      targetDate: string
    }
  6. Add a const that will be your title:

    //react/Countdown.tsx
    const titleText = title || <FormattedMessage id="countdown.title" />
  7. Now, join the title to the countdown to render. To do so, define a container outside. Besides, the text for the title will be passes using the prop title:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({
      title,
      targetDate,
    }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00',
      })
    
      const titleText = title || <FormattedMessage id="countdown.title" />
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
        <div className={`${handles.container} t-heading-2 fw3 w-100 c-muted-1`}>
          <div className={`${handles.title} db tc`}>{titleText}</div>
          <div className={`${handles.countdown} db tc`}>
            {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
          </div>
        </div>
      )
    }

    Note that three new handles are used: container, countdown and title. Therefore, remember to declare them in the const CSS_HANDLES, seen in the previous step:

    const CSS_HANDLES = ["container", "countdown", "title"]
  8. At last, it is needed to add the title prop in the schema:

    //react/Countdown.tsx
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {
    +   title: {
    +     title: 'I am a title',
    +     type: 'string',
    +     default: null,
    +   },
        targetDate: {
          title: 'Final date',
          description: 'Final date used in the countdown',
          type: 'string',
          default: null,
        },
      },
    }

Done! Now, to try out your store in another languages, you just need to add the query string /?cultureInfo=pt-br or /?cultureInfo=es-ar on the URL, for example. By using the first URL, the expected result is this one:

image

Linking an app and using it on a store's theme

Linking an app and using it on a store's theme

Introduction

To develop a store front block, like the ones provided natively in Store Framework, we use the UI development library React.js.

A little about the tool

React's basic development unit is a component, in which should be implemented all-in-one the logical operation, visual interface and data retrieval of an UI element. Following the most recent recommendation, we will focus our usage in the Hook API, not using class definition for component building.

In VTEX IO, we adopt Typescript as default language for frontend programming. Despite the complexity of learning new syntaxes, the effort is quickly rewarded! Using Typescript, the bug anticipation is enhanced, because of its static typing. Besides that, with the right IDEs, it's possible to increase the development speed with a smarter code completion of the code objects.

In this course, we'll use Typescript exclusively. If you're not familiar with the language, it will be a great chance to give it a try!

Step objective

Since you're already familiar to Store Framework, you know that we use blocks, like shelf and sku-selector, to create a VTEX IO store. In this step you're going to create a block that is going to be used in your store's home page theme.

Setting up our test bot

It's important for you to have our test bot installed in this course repository so we can see your progress, even though it does not contains any tests or evaluation on each step. So as to install it, follow the steps below:

  1. Open our test bot installation page and click on Configure;

  2. Select the Only selected repositories option, then click on Select repositories and type in store-block;

  3. Click on VincenzoConte/store-block and then on Install.

Activity

  1. In the local template cloned, open up the Countdown.tsx file:

    //react/Countdown.tsx
    import React from 'react'
    
    interface CountdownProps {}
    
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({}) => {
      return <div></div>
    }
    
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {},
    }
    
    export default Countdown
  2. Add an h1 tag inside the component and link it in your terminal, using the command vtex link.

    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({}) => {
    -   return <div></div>
    +   return (
    +     <div>
    +       <h1>Countdown Test</h1>
    +     </div>
    +   )
    }

    IMPORTANT: In order to the component that you've just linked to be seen in a functional store, you need to declare the block that the app defines in a theme. For that, hereby, we need to first have a theme to add the app to. In this course, we'll use the Store Theme. To clone the repository just run a:

    git clone https://github.com/vtex-apps/store-theme.git
    
  3. To avoid conflicts, go to your terminal and unlink any theme or apps you have linked. To do that, head just run the following command:

    vtex unlink --all
    
  4. With the repository cloned, go to its folder (cd store-theme) and link the theme on your workspace:

    vtex link
    

    IMPORTANT: At this point, you need to have two terminals opened and running vtex link. The first one contains the link of the custom block that you're creating and the second one refers to the store-theme, the theme you're using to insert your custom block on.

  5. Now, with both links active (theme and custom block), in order to use the app on the theme, we have to add it to the theme's dependencies, which, is in the manifest.json. Therefore, head to the theme's manifest in the store-theme folder and add vtex.countdown as a dependency. Its version is defined in its manifest (0.0.1). The manifest will then have one extra line like it is defined below:

    {
        ...
        "dependencies": {
            ...
    +        "vtex.countdown": "0.x",
            ...
        },
        ...
    }
  6. Lastly, we need to add the block to the store. Inside the file store-theme/store/blocks/home/home.jsonc, declare countdown block:

    {
        "store.home": {
            "blocks": [
                "countdown",
                ...
            ]
            ...
        }
        ...
    }
    

The expected result is to find a h1 in the top of the store, you can see it below:

image

Connecting _backend_ and _frontend_

Connecting backend and frontend

Introduction

Now we will learn how to retrieve data from the backend and display it in the interface. VTEX IO uses GraphQL as a language/technology for data transfer, which makes programming our components quite simple. We will modify our Countdown component to search for the targetDate of the releaseDate field of a VTEX product. To perform GraphQL queries in React, the Apollo Client is used, a state management lib that facilitates the integration of a GraphQL API with the front-end application.

The Apollo Client lib offers native integration with React, through hooks. Thus, making a query means using a hook that will not only perform the queries and fetch the data but will also provide caching and updating the UI state. This integration, called react-apollo is already declared in package.json.

Preparation

  • To implement this functionality, add our countdown block on the product page and also do our tests on this page as well. To do this, do the following:
  1. On your cloned theme (store-theme) access the store/blocks/product.jsonc file and, on the flex-layout.col#right-col block add the countdown block, right before the buy-button:

        "product-gifts",
    +	 "countdown",
        "flex-layout.row#buy-button",
        "availability-subscriber",
  2. Now, run vtex link on your theme again (if the process is not already running). It's done! Now our block is on the product page. Access any of these pages and see the rendered Countdown component.

Release Date Query

  1. First, create a folder react/queries and add a productReleaseDate.graphql file to it that will contain the query to be made. In particular, this query will receive a term, which will be the product slug to be retrieved at the launch date. It will call the resolver product, already available through thevtex.search-graphql app, and we will retrieve only the field we need.

    query productReleaseDate($slug: String){
        product(slug: $slug) {
            releaseDate
        }
    }

    Note that the query will need the slug of the product we are looking for. To do so, retrieve this information of the VTEX Product context.

  2. To use this query, it is necessary to add the vtex.search-graphql app as a dependency on your app. We will also need to use the useProduct hook, exported by the vtex.product-context the app, to retrieve the product slug that is loaded on the page. To do this, in your app's manifest.json, add in dependencies:

    "vtex.search-graphql": "0.x",
    "vtex.product-context": "0.x"
    
  3. Now, it is necessary to import the useQuery hooks, to make the query that will return the data we described, and useProduct, to give us information about the current product slug. In addition, it is also necessary to import the query defined previously, which is found in the file productReleaseDate.graphql.

    // react/Countdown.tsx
    import React from 'react'
    ...
    +import { useQuery } from 'react-apollo'
    
    +import useProduct from 'vtex.product-context/useProduct'
    
    +import productReleaseDate from './queries/productReleaseDate.graphql'

    It is important to higlight that there is the possibility of your IDE showing an error while importing product-context.

    The prop targetDate and the definition of DEFAULT_TARGET_DATE will no longer be necessary, so you can remove them and adjust the imports, in case of not using some functions anymore.

  4. After that, define the query using the productReleaseDate imported and the useQuery hook, you can find the product data in useProduct hook. Since they are hooks, they only work inside react functional components.

    + const { product } = useProduct()
    + const { data, loading, error } = useQuery(productReleaseDate, {
    +   variables: {
    +     slug: product?.linkText
    +   },
    +   ssr: false
    + })

    linkText will be the same as 'red-front-loading-washer', for example, when your component is rendered in this product's page.

  5. Now that we're using our block in pages that have the product context, it's important to test if this context exists. To do that, let's add the following code block:

    if (!product) {
      return (
        <div>
          <span>There is no product context.</span>
        </div>
      )
    }
  6. Besides, it is important to deal with the cases in which there is no data fetched when using useQuery and before returning the main component: loading and error In those cases, it is possible to return a span in the countdown component, such as the example below:

    if (loading) {
      return (
        <div>
          <span>Loading...</span>
        </div>
      )
    }
    if (error) {
      return (
        <div>
          <span>Error!</span>
        </div>
      )
    }
  7. After sending the changes, access a product page and note that the query is working through a console.log({data}) after calling useQuery, which should show something like this:

    {
      data: {
        product: {
          releaseDate: '2019-01-01T00:00:00"',
          __typename:  "Product"
        }
      }
    }
  8. At last, but not least, to make Countdown set the hours for the product's releaseDate, change the tick function parameter. You can also remove the props received in the component, as they will no longer be used.

    -tick(targetDate, setTime)
    +tick(data?.product?.releaseDate, setTime)

Result using the Red Front-Loading Washer product:

In case of having cases that the countdown is going up or with negative values, don't worry! It's related to the fact that some releaseDate can be in the past.

image


Well done!

This is the last step of the Store Block course, you did really well and we hope you've learned a lot until this moment. Congratulations!

If you want to continue learning more about how to develop using VTEX IO, we encourage you to start our next course, which focus on teaching how to develop services on top of VTEX IO. You can find it in the VTEX IO Service Course on Learning Lab.

Getting to know an app on VTEX IO

Getting to know an app on VTEX IO

Introduction

Before we start, it's necessary to remind some important concepts of the logical for a better understanding of the logical workflow when developing an app.

manifest.json

vendor

It defines the name of the VTEX account that is developing the app. This account is responsible for its maintenance and distribution (the app can be installed in other accounts or only in its own)

The vtex vendor is used for native apps

name

It identifies the name of the application. It should not contain any special characters (except from -) or uppercase characters.

version

It identifies the current app version. We use the Semantic Versioning 2.0.0 specification for versioning. The format is well defined, divided in patch, minor and major releases.

You can find bellow a summary of the specification:

  • Patches: Should be used for bug fixes that are backwards compatible
  • Minors: Should be used to add a new backwards compatible feature
  • Majors: Should be used when API incompatible changes are made (breaking changes)

For example: If an API is at version 2.3.2 and it adds a new non breaking change feature, it can then be updated to version 2.4.0.

At the moment the deployment is made, there is a worker called housekeeper which is responsible for updating automatically the new version for every account. It will, therefore, update all new minor and patch releases because of its backwards compatibility. It will not, however, automatically update major versions since it might come with dependency changes.

dependencies

An app might depend on other applications. This field lists all of the necessary dependencies for the correct app functioning.

Example

In the example of the manifest.json structure below, it's possible to see characteristics pointed out above. In particular, the app version is 0.0.1 and these numbers correspond respectively to its major, minor and patch.

{
  "vendor": "vtex",
  "name": "countdown",
  "version": "0.0.1",
  "title": "Countdown",
  "description": "Countdown component",
  "defaultLocale": "pt-BR",
  "builders": {
    "messages": "1.x",
    "store": "0.x",
    "react": "3.x"
  },
  "mustUpdateAt": "2019-04-02",
  "scripts": {
    "postreleasy": "vtex publish --verbose"
  },
  "dependencies": {
    "vtex.styleguide": "9.x",
    "vtex.css-handles": "0.x"
  },
  "$schema": "https://raw.githubusercontent.com/vtex/node-vtex-a pi/master/gen/manifest.schema"
}

Modifying the countdown block to have configurable styles

Modifying the countdown block to have configurable styles

Introduction

Now that we have implemented the countdown, how about adding a little customization? In this step, you will learn basic concepts about CSS handles and Tachyons to customize the style of your app.

CSS Handles

CSS handles are used to customize your store's components through CSS classes in the theme code. All settings are defined through the app vtex.css-handles, responsible for declaring all the customization points of your block.

By defining the names of your handles and adding them to their respective HTML elements, it is possible to give the theme's user customization points that allow them to create flexible layouts.

Tachyons

Tachyons is a framework for functional CSS. Unlike other known frameworks, like Bootstrap, it does not have "pre-built" UI components. In fact, its purpose is, precisely, separate the CSS rules into small, reusable parts. This type of strategy is commonly known as Subatomic Design System and, if you are interested, you can find a reference in this link. This strategy makes frameworks like Tachyons very flexible, scalable and fast.

A lot of the Tachyons' definitions can be changed, so that your store will have a more customized style. To do this, just define a JSON file in the styles / configs folder; this information can be found in more detail at: Build a store using VTEX IO - Customizing styles.

Activity

  1. Import the useCssHandles hook. To do so, return to Countdown.tsx and do the import:

    // react/Countdown.tsx
    import { useCssHandles } from "vtex.css-handles"
  2. Besides, define in a Array all necessary handles (in this case, only 'countdown' will be used):

    // react/Countdown.tsx
    const CSS_HANDLES = ["countdown"]
  3. Use the useCssHandles in the component Countdown to define the countdown handle:

    // react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
    + const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
        <div>
          <h1>
            { `${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}` }
          </h1>
        </div>
      )
    }
  4. At last, it is needed to use the handle in the component to see the customization. For this, use the prop className with the classes to be used and the Tachyons classes, for global styles.

    // react/Countdown.tsx
    import React from 'react'
    ...
    
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate = DEFAULT_TARGET_DATE }) => {
      const [timeRemaining, setTime] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
    +   <div className={`${handles.countdown} c-muted-1 db tc`}>
          {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
        </div>
      )
    }

Let's see the result?

image

Componentizing the countdown block

Componentizing the countdown block

Introduction

In this step, the app has two main elements: the title and the countdown. However, in order to obtain greater positioning and customization flexibility, it is interesting that they are separated into two distinct blocks. For this, it is necessary to briefly introduce the concept of interfaces, and then a new Title component will be developed. An example of customization in terms of positioning, which will be covered in this step, is:

What if I wanted the title to be under or beside the counter?

Interface

An interface works like a contract, with well-defined restrictions on how the blocks will work together. It then defines a mapping that creates a Store Framework block, from a React component. It is important to highlight that the use of interfaces, in order to separate an app in several interfaces, makes the customization power much greater.

When defining an app in the interface, the component property is responsible for defining the React component that will be used. It is important to note that the name of component must be the same as the file name of the component inside the react/ folder.

interfaces.json examples:

{
  "countdown": {
    "component": "Countdown"
  }
}

Activity

Now, you are going to separate the title from the countdown block and add it to the store below the countdown.

Altering the Countdown component

  1. First, remove the imports, the title from the interface and change the CSS handles const, CSS_HANDLES:

    //react/Countdown.tsx
    import React, { useState } from 'react'
    import { TimeSplit } from './typings/global'
    import { tick, getTwoDaysFromNow } from './utils/time'
    import { useCssHandles } from 'vtex.css-handles'
    -import { FormattedMessage } from 'react-intl'
    
    interface CountdownProps {
      targetDate: string,
    -  title: string
    }
    
    const DEFAULT_TARGET_DATE = getTwoDaysFromNow()
    -const CSS_HANDLES = ['container', 'countdown', 'title']
    +const CSS_HANDLES = ['countdown']
  2. Now, in the component itself, remove the title as a prop given and also the title text constant, which changes what is being rendered:

    //react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({
    - title,
      targetDate = DEFAULT_TARGET_DATE,
    }) => {
      const [
        timeRemaining,
        setTime
      ] = useState<TimeSplit>({
        hours: '00',
        minutes: '00',
        seconds: '00'
      })
    
    - const titleText = title || <FormattedMessage id="countdown.title" />
      const handles = useCssHandles(CSS_HANDLES)
    
      tick(targetDate, setTime)
    
      return (
    -   <div className={`${handles.container} t-heading-2 fw3 w-100 pt7 pb6 c-muted-1 db tc`}>
    -     <div className={`${handles.title} db tc`}>
    -       { titleText }
    -     </div>
          <div className={`${handles.countdown} db tc`}>
            {`${timeRemaining.hours}:${timeRemaining.minutes}:${timeRemaining.seconds}`}
          </div>
    -   </div>
      )
    }
  3. At last, remove the title from the schema:

    //react/Countdown.tsx
    Countdown.schema = {
      title: 'editor.countdown.title',
      description: 'editor.countdown.description',
      type: 'object',
      properties: {
    -   title: {
    -     title: 'I am a title',
    -     type: 'string',
    -     default: null,
    -   },
        targetDate: {
          title: 'Final date',
          description: 'Final date used in the countdown',
          type: 'string',
          default: null,
        },
      },
    }

Creating a new component

  1. Create a new file in the /react directory, named Title.tsx, it will be the new title component. In it, some imports are needed. The basic structure of the code is very similar to the Countdown component's. Afer doing that, add the imports needed and the CSS handles constant:

    //react/Title.tsx
    import React from "react"
    import { FormattedMessage } from "react-intl"
    import { useCssHandles } from "vtex.css-handles"
    
    const CSS_HANDLES = ["title"] as const
  2. Now, it's necessary to change the component's function:

    //react/Title.tsx
    const Title: StorefrontFunctionComponent<TitleProps> = ({ title }) => {
      const handles = useCssHandles(CSS_HANDLES)
      const titleText = title || <FormattedMessage id="countdown.title" />
    
      return (
        <div
          className={`${handles.title} t-heading-2 fw3 w-100 c-muted-1 db tc`}
        >
          {titleText}
        </div>
      )
    }
  3. At last, add the interface, the schema and the export:

    //react/Title.tsx
    interface TitleProps {
      title: string
    }
    
    Title.schema = {
      title: "editor.countdown-title.title",
      description: "editor.countdown-title.description",
      type: "object",
      properties: {
        title: {
          title: "I am a title",
          type: "string",
          default: null,
        },
      },
    }
    
    export default Title

Changing the interfaces.json file

By now, there are two components in the app: the title and the countdown. However, it is necessary to change the interfaces.json file, which is in the store folder. It is needed to declare each one separately. At first, our interface only contained the Countdown. It is needed to add the other component:

{
  "countdown": {
    "component": "Countdown"
  },
+   "countdown.title": {
+     "component": "Title"
+   }
}

Adding internationalization

It is also needed to add to the Messages the translations whose keys are the strings of the schema that we included in the Title.tsx file above. As seen in the Messages step, go to the /messages folder, and add the necessary translations to each file (pt.json, es.json and en.json). Below is an example for the case of the en.json file:

 {
   "countdown.title": "Countdown",
   "editor.countdown.title": "Countdown",
   "editor.countdown.description": "Countdown component",
+  "editor.countdown-title.title": "Countdown title",
+  "editor.countdown-title.description": "Title component",
 }

Adding the new block to the store home

Finally, to see the changes, go back to the theme to change it to include the new block. To do so, simply add the title to home! Same as the countdown, it is necessary to add countdown.title as a block in the theme of your store, in the store-theme file home.jsonc.

//home.jsonc
 {
   "store.home": {
     "blocks": [
       "countdown",
+      "countdown.title",
       ...
     ]
   },
   ...
 }

Done! Now let's see how the result should look like:
image

Making the countdown block customizable

Making the countdown block customizable

Introduction

Now we have an h1 element rendered, it's possible to used it to display information that depend on the component's properties (props). For that, some concepts will be shown, given that they are essential for the app development.

Concepts

  • Hook

    Hooks are APIs that allow using React features inside functional components. Without the hooks, a functional React component is only able to render UI elements. They, hereby, allow, among other things, state storage between different renders and execute side effets to the component's life cycle. Note: They do not work inside classes.

    e.g:

    const [count, setCount] = useState(0)
  • props interface

    Defines the props Typescript typing that the component will receive, allowing IDE's intellisense about the created component.

    interface CountdownProps {
      exampleProp: string
    }
  • Block's schema

    In VTEX IO, we offer a content management tool called Site Editor. With it, through VTEX Admin, it's possible to change images, texts and behaviours of blocks without having to change the Store's code.

    In order for your block to accept user customizations, you need to export a schema in the React component responsible for the block using JSON schema. This will, automatically, generate a form in Site Editor linked to the block that you're developing. Here's a schema example:

    // react/Countdown.tsx
    Countdown.schema = {
        title: 'editor.countdown.title',
        description: 'editor.countdown.description',
        type: 'object',
        properties: {},
    }

    The schema is also responsible for defining the labels that will be displayed to the user when editing the block content on the form.

Atividade

  1. In the interface defined in Countdown.tsx, add a prop called targetDate, its type is string. We are, hence, defining a component prop that will be used to initialize the countdown.

    The prop definition itself is made through its declaration in the CountdownProps interface in the Countdown.tsx file, shown previously. Thus, add a line that define the targetDate prop of type string:

    // react/Countdown.tsx
    interface CountdownProps {
    +   targetDate: string    
    }
  2. Now, we need to use it on the component, substituting the text used used previously, Countdown Test, for another, using Site Editor.

    Keep in mind that targetDate will be used to define the countdown ending date. However, for now, it will work as a dummy field.

    First, change the component in order for it to use the targetDate prop. To do that, you need to use its variable inside the h1 of the React component.

    // react/Countdown.tsx
    const Countdown: StorefrontFunctionComponent<CountdownProps> = ({ targetDate }) => {
      return (
        <div>
          <h1>{ targetDate }</h1>
        </div>
      ) 
    }
  3. Furthermore, to be able to edit this property through Site Editor, it's necessary to add that same prop to the schema. This is done by adding the targetDate key to the properties object of the schema:

// react/Countdown.tsx
Countdown.schema = {
  title: 'editor.countdown.title',
  description: 'editor.countdown.description',
  type: 'object',
  properties: {
+   targetDate: {
+      title: 'Final date',
+      description: 'Final date used in the countdown',
+      type: 'string',
+      default: null,
+   },
  },
}

All set! Now you can change the text content through Site Editor. Go ahead to the Site Editor and click on Countdown on the side menu, this will open an edit menu, like the shown bellow:

image

Now, in the field below the title, type the date in the format AAAA-MM-DD and see the change, that will then show the text you've typed!

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.