Documentation
Feedback
Guides
Storefront Development

Storefront Development
FastStoreExtending the FastStore APIAPI extensions - Use cases
Adding Installment Information in the Product Details Page
This guide illustrates how you can display available installment options for products on your Product Details Page (PDP).
For detailed instructions on API extensions, refer to API extensions guide.

Context

You want to display installment details (number, value, payment system) on the PDP for products with installments. This functionality allows customers to see installment details directly on the product page, aiding their purchase decision.

Implementation

Create the GraphQL files

First, you need to set up the necessary GraphQL files to retrieve and structure the installment data.
  1. In your store repository, go to the src folder, if you don’t have one already, create a new graphql folder.
  2. Inside graphql, create the vtex folder.
  3. In the vtex folder, create two other subfolders, resolvers and typeDefs.
For further details on code implementation, see the vtex folder available in the playground.store repository.

_10
src
_10
â”— đź“‚ graphql
_10
â”— đź“‚vtex
_10
┣ 📂 resolvers
_10
â”— đź“‚ typeDefs

Define the types

Now that we have our file structure in place, let's define the data structure for our installment information using GraphQL.
In the typeDefs folder, create a product.graphql file to define the schema. Add the following schema definitions.
  • Installments: Specifies the structure of each installment option. Each installment has properties for:
  • installmentPaymentSystemName: The name of the payment system used (e.g., Credit Card).
  • installmentValue: The value of each installment.
  • installmentInterest: The interest rate applied per installment.
  • installmentNumber: The total number of installments offered.
  • StoreProduct: This type is being extended to include a new field called availableInstallments. This field is a list of installment objects, representing all the available installment options for the product.
product.graphql

_13
type Installments {
_13
installmentPaymentSystemName: String!
_13
installmentValue: Float!
_13
installmentInterest: Float!
_13
installmentNumber: Float!
_13
}
_13
_13
extend type StoreProduct {
_13
"""
_13
Retrieve available installment data extending StoreProduct
_13
"""
_13
availableInstallments: [Installments!]!
_13
}

Create the resolvers

Now that we've defined the structure of our installment data (GraphQL types), let's create the logic to retrieve and format this data using a resolver function. Resolvers essentially act as gateways between your frontend and backend, processing data requests.
In the resolvers folder, create a product.ts file to handle the installment data logic. Add the following code.
  • productResolver: Defines a resolver for the StoreProduct type.
  • availableInstallments: Function that retrieves the Installments data from the commertialOffer property of the first seller (sellers[0]).
  • installments.length: Check if there are any installments (installments.length). If not, an empty array is returned.
  • The code iterates through each installment and maps it to a new object with the desired properties (installmentPaymentSystemName, installmentValue, etc.).
product.graphql
product.ts

_22
import type { StoreProductRoot } from "@faststore/core/api";
_22
_22
const productResolver = {
_22
StoreProduct: {
_22
availableInstallments: (root: StoreProductRoot) => {
_22
const installments = root.sellers?.[0]?.commertialOffer?.Installments;
_22
_22
if (!installments.length) {
_22
return [];
_22
}
_22
_22
return installments.map((installment) => ({
_22
installmentPaymentSystemName: installment.PaymentSystemName,
_22
installmentValue: installment.Value,
_22
installmentInterest: installment.InterestRate,
_22
installmentNumber: installment.NumberOfInstallments,
_22
}));
_22
},
_22
},
_22
};
_22
_22
export default productResolver;

Consolidating the resolvers

In the resolvers folder, create an index.ts file to consolidate the resolvers.
  • By default exporting resolvers, this file acts as a central hub for all your resolvers.
  • resolvers:Combines the imported resolver with any other resolvers you might have in your project (represented by the ellipsis ...).
product.graphql
product.ts
index.ts

_10
import { default as StoreProductResolver } from "./product";
_10
_10
const resolvers = {
_10
...StoreProductResolver,
_10
};
_10
_10
export default resolvers;

Using fragments

Now that we've defined the availableInstallments field using GraphQL types and resolvers, we need to specify where this data will be used in your storefront queries. This is achieved through GraphQL fragments.
  1. In the src folder of your store code, create a fragments folder.
  2. In the fragments folder, create the following files:
    • ClientProduct.ts: Defines the Client-Side fragment.
    • ServerProduct.ts: Defines the Server-Side fragment.
  3. In the ClientProduct.ts file, define the GraphQL fragment for retrieving installment data.
  • gql: Imported from @faststore/core/api to construct the GraphQL fragment.
  • ClientProduct: Fragment to indicate it extends the product query.
  • The fragment defines the specific fields we want to retrieve from the availableInstallments data structure.
product.graphql
product.ts
index.ts
ClientProduct.ts

_14
import { gql } from "@faststore/core/api";
_14
_14
export const fragment = gql(`
_14
fragment ClientProduct on Query {
_14
product(locator: $locator) {
_14
availableInstallments {
_14
installmentPaymentSystemName
_14
installmentValue
_14
installmentInterest
_14
installmentNumber
_14
}
_14
}
_14
}
_14
`);

Adding server-side product fragment for installment details

To ensure consistency in data retrieval across client-side and server-side, add a product fragment focusing on installment details. In the ServerProduct.ts file, add the following code.
For further details on code implementation, see the fragments folder available in the playground.store repository.
product.graphql
product.ts
index.ts
ClientProduct.ts
ServerProduct.ts

_14
import { gql } from "@faststore/core/api";
_14
_14
export const fragment = gql(`
_14
fragment ServerProduct on Query {
_14
product(locator: $locator) {
_14
availableInstallments {
_14
installmentPaymentSystemName
_14
installmentValue
_14
installmentInterest
_14
installmentNumber
_14
}
_14
}
_14
}
_14
`);

Formatting installment values

For a more user-friendly display, you can format the installment values to include currency symbols and proper locale formatting.
  1. In the src folder of your store code, create a utils folder.
  2. Inside utils, create the file priceFormatter.ts and add the following.
  • FaststoreConfig: Imported to access the current store's locale and currency settings.
  • priceFormatter: This function takes a numeric value and formats it according to the store's locale and currency.
For further details on code implementation, see the utils folder available in the playground.store repository.
product.graphql
product.ts
index.ts
ClientProduct.ts
ServerProduct.ts
priceFormatter.ts

_10
import FaststoreConfig from "../../faststore.config.js";
_10
_10
export const priceFormatter = (value: number) => {
_10
return value.toLocaleString(FaststoreConfig.session.locale, {
_10
style: "currency",
_10
currency: FaststoreConfig.session.currency.code,
_10
});
_10
};

Create the new component with installments

Now that we've established the logic for retrieving installment data, let's create a new component to display this information alongside the buy button on the PDP.
  1. In the src/components folder, create two new folders:
    • BuyButtonWithDetails: This folder keeps the component for our enhanced buy button with installment details.
    • sections/CustomProductDetails: This folder keeps the logic for overriding the default PDP buy button component.
  2. Inside BuyButtonWithDetails folder, create two new files:
    • BuyButtonWithDetails.tsx
    • buy-button-with-details.module.scss
  3. Inside BuyButtonWithDetails.tsx add the following code.
  • priceFormatter: Format installment values.
  • styles: Stylesheet for the BuyButtonWithDeatils imported from the .scss file.
  • usePDP: Hook to retrieve the PDP context containing product and extension data.
  • We conditionally display the first installment option if it's interest-free (you can modify this to show all installments).
  • The component renders a section containing the installment information and the buy button.
product.graphql
product.ts
index.ts
ClientProduct.ts
ServerProduct.ts
priceFormatter.ts
BuyButtonWithDetails.tsx

_32
import { usePDP } from "@faststore/core";
_32
import { Button as UIButton, ButtonProps } from "@faststore/ui";
_32
import { priceFormatter } from "../../utils/priceFormatter";
_32
_32
import styles from "./buy-button-with-details.module.scss";
_32
_32
export function BuyButtonWithDetails(props: ButtonProps) {
_32
const context = usePDP();
_32
_32
const installment = context?.data?.product?.availableInstallments[0];
_32
const interestFree = installment.installmentInterest === 0 ?? false;
_32
_32
return (
_32
<section className={styles.buyButtonWithDetails}>
_32
{interestFree && (
_32
<span>
_32
{`${installment.installmentNumber} interest-free installment(s)`}
_32
<br />
_32
{`of ${priceFormatter(installment.installmentValue)} with ${
_32
installment.installmentPaymentSystemName
_32
}`}
_32
</span>
_32
)}
_32
_32
<UIButton {...props} variant="primary">
_32
Buy Button
_32
</UIButton>
_32
</section>
_32
);
_32
}
_32
_32
export default BuyButtonWithDetails;

Creating the stylesheet for the component

Inside the buy-button-with-details.module.scss, add the following code. The stylesheet styles the component using SCSS. It defines styles for the installment information container and the buy button itself.
product.graphql
product.ts
index.ts
ClientProduct.ts
ServerProduct.ts
priceFormatter.ts
BuyButtonWithDetails.tsx
buy-button-with-details.module.scss

_16
.buyButtonWithDetails {
_16
> span {
_16
display: flex;
_16
justify-content: center;
_16
margin-bottom: var(--fs-spacing-4);
_16
text-align: center;
_16
font-size: var(--fs-text-size-1);
_16
}
_16
_16
[data-fs-button] {
_16
width: 100%;
_16
[data-fs-button-wrapper] {
_16
background-color: var(--fs-color-neutral-7);
_16
}
_16
}
_16
}

Create a custom section

By including the CustomProductDetails section in the PDP, you replace the default buy button component with your enhanced BuyButtonWithDetails component, which displays both the buy button and the installment information.
In the folder CustomProductDetails, create the CustomProductDetails.tsx and add the following code.
For further details on code implementation, see the utils folder available in the playground.store repository.
product.graphql
product.ts
index.ts
ClientProduct.ts
ServerProduct.ts
priceFormatter.ts
BuyButtonWithDetails.tsx
buy-button-with-details.module.scss
CustomProductDetails.tsx

_11
import { getOverriddenSection, ProductDetailsSection } from "@faststore/core";
_11
import { BuyButtonWithDetails } from "../../BuyButtonWithDetails/BuyButtonWithDetails";
_11
_11
const CustomProductDetails = getOverriddenSection({
_11
Section: ProductDetailsSection,
_11
components: {
_11
BuyButton: { Component: BuyButtonWithDetails },
_11
},
_11
});
_11
_11
export default CustomProductDetails;

Create the GraphQL files

First, you need to set up the necessary GraphQL files to retrieve and structure the installment data.
  1. In your store repository, go to the src folder, if you don’t have one already, create a new graphql folder.
  2. Inside graphql, create the vtex folder.
  3. In the vtex folder, create two other subfolders, resolvers and typeDefs.
For further details on code implementation, see the vtex folder available in the playground.store repository.

Define the types

Now that we have our file structure in place, let's define the data structure for our installment information using GraphQL.
In the typeDefs folder, create a product.graphql file to define the schema. Add the following schema definitions.
  • Installments: Specifies the structure of each installment option. Each installment has properties for:
  • installmentPaymentSystemName: The name of the payment system used (e.g., Credit Card).
  • installmentValue: The value of each installment.
  • installmentInterest: The interest rate applied per installment.
  • installmentNumber: The total number of installments offered.
  • StoreProduct: This type is being extended to include a new field called availableInstallments. This field is a list of installment objects, representing all the available installment options for the product.

Create the resolvers

Now that we've defined the structure of our installment data (GraphQL types), let's create the logic to retrieve and format this data using a resolver function. Resolvers essentially act as gateways between your frontend and backend, processing data requests.
In the resolvers folder, create a product.ts file to handle the installment data logic. Add the following code.
  • productResolver: Defines a resolver for the StoreProduct type.
  • availableInstallments: Function that retrieves the Installments data from the commertialOffer property of the first seller (sellers[0]).
  • installments.length: Check if there are any installments (installments.length). If not, an empty array is returned.
  • The code iterates through each installment and maps it to a new object with the desired properties (installmentPaymentSystemName, installmentValue, etc.).

Consolidating the resolvers

In the resolvers folder, create an index.ts file to consolidate the resolvers.
  • By default exporting resolvers, this file acts as a central hub for all your resolvers.
  • resolvers:Combines the imported resolver with any other resolvers you might have in your project (represented by the ellipsis ...).

Using fragments

Now that we've defined the availableInstallments field using GraphQL types and resolvers, we need to specify where this data will be used in your storefront queries. This is achieved through GraphQL fragments.
  1. In the src folder of your store code, create a fragments folder.
  2. In the fragments folder, create the following files:
    • ClientProduct.ts: Defines the Client-Side fragment.
    • ServerProduct.ts: Defines the Server-Side fragment.
  3. In the ClientProduct.ts file, define the GraphQL fragment for retrieving installment data.
  • gql: Imported from @faststore/core/api to construct the GraphQL fragment.
  • ClientProduct: Fragment to indicate it extends the product query.
  • The fragment defines the specific fields we want to retrieve from the availableInstallments data structure.

Adding server-side product fragment for installment details

To ensure consistency in data retrieval across client-side and server-side, add a product fragment focusing on installment details. In the ServerProduct.ts file, add the following code.
For further details on code implementation, see the fragments folder available in the playground.store repository.

Formatting installment values

For a more user-friendly display, you can format the installment values to include currency symbols and proper locale formatting.
  1. In the src folder of your store code, create a utils folder.
  2. Inside utils, create the file priceFormatter.ts and add the following.
  • FaststoreConfig: Imported to access the current store's locale and currency settings.
  • priceFormatter: This function takes a numeric value and formats it according to the store's locale and currency.
For further details on code implementation, see the utils folder available in the playground.store repository.

Create the new component with installments

Now that we've established the logic for retrieving installment data, let's create a new component to display this information alongside the buy button on the PDP.
  1. In the src/components folder, create two new folders:
    • BuyButtonWithDetails: This folder keeps the component for our enhanced buy button with installment details.
    • sections/CustomProductDetails: This folder keeps the logic for overriding the default PDP buy button component.
  2. Inside BuyButtonWithDetails folder, create two new files:
    • BuyButtonWithDetails.tsx
    • buy-button-with-details.module.scss
  3. Inside BuyButtonWithDetails.tsx add the following code.
  • priceFormatter: Format installment values.
  • styles: Stylesheet for the BuyButtonWithDeatils imported from the .scss file.
  • usePDP: Hook to retrieve the PDP context containing product and extension data.
  • We conditionally display the first installment option if it's interest-free (you can modify this to show all installments).
  • The component renders a section containing the installment information and the buy button.

Creating the stylesheet for the component

Inside the buy-button-with-details.module.scss, add the following code. The stylesheet styles the component using SCSS. It defines styles for the installment information container and the buy button itself.

Create a custom section

By including the CustomProductDetails section in the PDP, you replace the default buy button component with your enhanced BuyButtonWithDetails component, which displays both the buy button and the installment information.
In the folder CustomProductDetails, create the CustomProductDetails.tsx and add the following code.
For further details on code implementation, see the utils folder available in the playground.store repository.

_10
src
_10
â”— đź“‚ graphql
_10
â”— đź“‚vtex
_10
┣ 📂 resolvers
_10
â”— đź“‚ typeDefs

Results

Once you have set your development mode, you can see the changes locally by accessing a PDP, for example, https://localhost:3000/adidas-mens-performance-polo-green-night-99984111/p, and you will see the installment information for the product.

Before

The PDP before adding the installment.
{"base64":"  ","img":{"width":948,"height":571,"type":"png","mime":"image/png","wUnits":"px","hUnits":"px","length":215607,"url":"https://vtexhelp.vtexassets.com/assets/docs/src/before-installment___c06c92a26445e0dc97a33981f893358e.png"}}

After

After applying the logic for the installments, the information is available above the Buy Button.
{"base64":"  ","img":{"width":929,"height":676,"type":"png","mime":"image/png","wUnits":"px","hUnits":"px","length":240060,"url":"https://vtexhelp.vtexassets.com/assets/docs/src/after-installment___77227bfcffcf9a25800effe9790100e1.png"}}
Contributors
1
Photo of the contributor
+ 1 contributors
Was this helpful?
Yes
No
Suggest edits (Github)
Contributors
1
Photo of the contributor
+ 1 contributors
On this page