Skip to main content

Home page

This section is part of a the tutorial series to build a Product Highlights example Extension.

What you’ll learn

In this section, you'll use React, MongoDB, and Nitrozen components to build your Extension home page.

This change consists of three steps:

  • Create schema for saving product and its highlights using mongodb.
  • Make changes in the Extension backend.
  • Add additional components to the Home page of the Extension Frontend.

Step 1: Create MongoDB config

The app needs a database to store the Product details so that merchants can view and edit the saved product highlights. For this we will require mongo connection.

  • Add the following dependency inside ./pom.xml file

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>2.7.5</version>
    </dependency>
  • Create a new file /com/fynd/example/java/db/MongoConfig.java and add the following code:

    package com.fynd.example.java.db;

    import com.fynd.example.java.properties.Config;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.mongodb.core.MongoTemplate;
    import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

    @Configuration
    public class MongoConfig {

    @Autowired
    Config config;

    @Bean
    public MongoTemplate mongoTemplate() {
    String mongodbUri = config.getMongodbUri();
    return new MongoTemplate(new SimpleMongoClientDatabaseFactory(mongodbUri));
    }
    }

Step 2: Create MongoDB schema

The database collection includes the product highlights, as well as the basic details about the product such as name, product brand, product slug, and product item code.

  • Create new /com/fynd/example/java/db/Product.java class

    package com.fynd.example.java.db;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fynd.example.java.helper.models.Price;
    import lombok.*;

    import java.util.List;

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public class Product {

    @JsonProperty("name")
    private String name;

    @JsonProperty("image")
    private String image;

    @JsonProperty("brand_name")
    private String branchName;

    @JsonProperty("category_slug")
    private String categorySlug;

    @JsonProperty("highlights")
    private List<String> highlights;

    @JsonProperty("price")
    private Price price;

    @JsonProperty("enablePriceDrop")
    private Boolean enablePriceDrop;
    }
  • Also crate /com/fynd/example/java/db/ProductHighlight.java class

    package com.fynd.example.java.db;

    import lombok.*;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import org.springframework.data.mongodb.core.mapping.Document;

    @Document(collection = "product-highlights")
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    public class ProductHighlight {

    @JsonProperty("company_id")
    private String companyId;

    @JsonProperty("application_id")
    private String applicationId;

    @JsonProperty("product_item_code")
    private Integer productItemCode;

    @JsonProperty("product_slug")
    private String productSlug;

    @JsonProperty("product")
    private Product product;

    @JsonProperty(value = "is_active", defaultValue = "false")
    private Boolean isActive;
    }
  • Create new /com/fynd/example/java/db/interfaces/ProductHighlightRepository.java file and add the following code to the file

    package com.fynd.example.java.db.interfaces;

    import com.fynd.example.java.db.ProductHighlight;
    import org.springframework.data.mongodb.repository.MongoRepository;
    import org.springframework.stereotype.Repository;

    import java.util.List;
    import java.util.Optional;

    @Repository
    public interface ProductHighlightRepository extends MongoRepository<ProductHighlight, String> {

    List<ProductHighlight> findByCompanyIdAndIsActive(String companyId);

    List<ProductHighlight> findByCompanyIdAndApplicationId(String companyId, String applicationId);

    Optional<ProductHighlight> findOneByCompanyIdAndApplicationIdAndProductItemCode(String companyId, String applicationId, Integer productItemCode);

    Optional<ProductHighlight> findOneByCompanyIdAndApplicationIdAndProductSlug(String companyId, String applicationId, String productSlug);

    Optional<ProductHighlight> findOneByCompanyIdAndProductItemCode(String companyId, Integer ProductItemCode);

    Optional<ProductHighlight> findOneByApplicationIdAndProductSlug(String applicationId, String productSlug);

    void deleteOneByCompanyIdAndApplicationIdAndProductItemCode(String companyId, String applicationId, Integer productItemCode);

    void deleteOneByCompanyIdAndApplicationIdAndProductSlug(String companyId, String applicationId, String productSlug);

    long countByCompanyIdAndApplicationIdAndIsActive(String companyId, String applicationId, Boolean isActive);
    }

Step 3: Update the backend API

  • Create a new file /com/fynd/example/java/controller/ProductController.java and add the following code

    package com.fynd.example.java.controller;

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fynd.example.java.db.ProductHighlight;
    import com.fynd.example.java.db.interfaces.ProductHighlightRepository;
    import com.fynd.extension.controllers.BasePlatformController;
    import com.fynd.extension.session.Session;
    import com.sdk.platform.PlatformClient;
    import com.sdk.platform.configuration.ConfigurationPlatformModels.ApplicationsResponse;
    import com.sdk.platform.configuration.ConfigurationPlatformModels.Application;
    import jakarta.servlet.http.HttpServletRequest;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    import java.util.*;

    @RestController
    @RequestMapping("/api/v1.0")
    @Slf4j
    public class ProductController extends BasePlatformController {

    @Autowired
    ProductHighlightRepository productHighlightRepository;

    @Autowired
    private ObjectMapper mapper;

    @GetMapping(value = "/applications")
    public ResponseEntity<ApplicationsResponse> getApplications(HttpServletRequest request) {
    try {
    PlatformClient platformClient = (PlatformClient) request.getAttribute("platformClient");
    Session fdkSession = (Session) request.getAttribute("fdkSession");

    String companyId = fdkSession.getCompanyId();

    ApplicationsResponse applications
    = platformClient.configuration.getApplications(1, 100, mapper.writeValueAsString(Collections.singletonMap("is_active", true)));

    Set<String> activeApplicationSet = new HashSet<>();
    List<ProductHighlight> productSchema = productHighlightRepository.findByCompanyIdAndIsActive(companyId);

    for (ProductHighlight product: productSchema) {
    activeApplicationSet.add(product.getApplicationId().toString());
    }

    for (Application application: applications.getItems()) {
    application.setIsActive(activeApplicationSet.contains(application.getId()));
    }

    return ResponseEntity.ok(applications);

    } catch(Exception e) {
    System.out.println(e.getMessage());
    throw new RuntimeException(e);
    }
    }
    }

Step 4: Changes in the Front End part

We’ll be using the Badge and Input components and SvgIcArrowNext Icon of the Nitrozen library

tip

Check out Nitrozen’s storybook for detailed documentation and usage instructions.

  1. Open /app/src/views/Home.jsx
  2. Delete the contents of the file.
  3. Add the following code:
import React, { useState, useEffect } from "react";
import { useNavigate, useParams } from 'react-router-dom'

import "./style/home.css";
import Loader from "../components/Loader";
import { Badge, SvgIcArrowNext, Input } from "@gofynd/nitrozen-react";
import MainService from "../services/main-service";

export default function Home() {
const [pageLoading, setPageLoading] = useState(false);
const [applicationList, setApplicationList] = useState([]);
const [allApplications, setAllApplications] = useState([]);

const navigate = useNavigate();
const { company_id } = useParams();

useEffect(() => {
fetchApplications();
}, []);

const fetchApplications = async () => {
setPageLoading(true);
try {
const { data } = await MainService.getAllApplications();
setAllApplications(data.items);
const temp = data.items.map((ele) => {
ele.text = ele.name;
ele.value = ele._id;
ele.image = ele.logo;
ele.logo = ele.image && ele.image.secure_url;
return ele;
});
setApplicationList(temp);
setPageLoading(false);
} catch (e) {
setPageLoading(false);
}
};

function searchApplication(event) {
let searchText = event.target.value;
if (!searchText) {
setApplicationList(allApplications.map((app) => app));
} else {
setApplicationList(
allApplications.filter((item) => {
return item.name.toLowerCase().includes(searchText.toLowerCase());
})
);
}
}

function clickOnSalesChannel(application_id) {
navigate(`/company/${company_id}/${application_id}/product-list`)
}

return (
<>
{pageLoading ? (
<Loader />
) : (
<div className="application-container">

<div className="saleschannel-title">Sales Channel</div>

<div className="search-box">
<Input
showSearchIcon
placeholder='search sales channels'
disabled={ Object.keys(allApplications).length === 0 ? true : false }
onChange={searchApplication}
/>
</div>

<div className="sales-channels-container">
{applicationList.map((application) => {
return (
<div className="app-box">

<div className="logo">
<img src={application.logo ? application.logo : "https://platform.fynd.com/public/admin/assets/pngs/fynd-store.png"} alt="logo" />
</div>

<div className="line-1">{application.name}</div>

<div className="line-2">{application.domain.name}</div>

<div className="button-and-arrow">
<div>
<Badge
fill
kind="normal"
state={application.is_active ? "success" : "disable"}
labelText={application.is_active ? "ACTIVE" : "INACTIVE"}
style={{
padding: "10px 6px"
}}
/>
</div>

<div className="card-arrow">
<div className="card-arrow-box"
onClick={() => clickOnSalesChannel(application._id)}
>
<SvgIcArrowNext
className="arrow-next"
/>
</div>
</div>

</div>

</div>
);
})}
{applicationList.length % 3 === 2 && (
<div className="app-box hidden"></div>
)}
</div>

</div>
)}
</>
);
}

Now, update the CSS file for the above code

  1. Open /app/src/views/style/home.css
  2. Delete the contents of the file.
  3. Add the following code:
caution

CSS written in this file will have an impact on the entire project.

html {
height: 100%;
width: 100%;
font-size: 8px;
}

body {
margin: 0;
font-family: Inter;
background-color: #f8f8f8 !important;
width: 100%;
height: 100%;
@media @mobile {
-webkit-tap-highlight-color: transparent;
}
}

.application-container {
font-family: Inter;
position: relative;
box-sizing: border-box;
background: #fff;
border: 1px solid #f3f3f3;
border-radius: 12px;
padding: 24px;
margin: 24px;
}

.saleschannel-title {
font-weight: 700;
font-size: 20px;
margin-bottom: 8px;
}

.search-box {
margin-top: 20px;
}

.sales-channels-container {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
grid-column-gap: 18px;
grid-row-gap: 18px;
margin-top: 20px;
width: calc(100% - 54px);
}

.app-box {
background-color: #ffffff;
border: 1px solid #e4e5e6;
padding: 20px;
border-radius: 12px;
}

.app-box .logo {
width: 48px;
height: 48px;
}

.app-box .logo img {
width: 100%;
height: auto;
}

.app-box .line-1 {
font-weight: 600;
font-size: 16px;
line-height: 26px;
margin-top: 20px;
}

.app-box .line-2 {
color: #9b9b9b;
line-height: 22px;
font-size: 12px;
}

.app-box + .app-box:nth-child(3n + 1) {
margin-left: 0;
}

/* card footer elements */
.app-box .button-and-arrow {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 40px;
}

.card-arrow-box {
border: 1px solid #2E31BE;
border-radius: 4px;
height: 36px;
width: 36px;
display: flex;
align-items: center;
justify-content: center;
}

.card-arrow-box:hover {
transition-duration: 0.4s;
background-color: #2E31BE;
cursor: pointer;
}

.arrow-next {
color: #2E31BE;
width: 16px;
height: auto;
}

.card-arrow-box:hover .arrow-next {
transition-duration: 0.4s;
color: #ffffff;
cursor: pointer;
}

.hidden {
visibility: hidden;
}

Step 5: Restart the server and launch the Extension

Extension home page


Was this section helpful?