# Visualizer UI Documentation

## Get Started

```html
<html>
  <head>
    <link href="https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/index.css" rel="stylesheet" />
  </head>
  <body>
    <div
      class="visualizer"
      data-role="visualizer"
      experienceId="<your experience id, optional if using hashExperienceId>"
      hashExperienceId="<your hashed experience id, optional if using experienceId>"
      sceneConfigurationLabel="<optional, the maximum width image size to use on mobile, a number from 0 to 2048>"
      sceneId="<optional, will lunch a scene by scene id>"
      defaultProduct="<optional, product sku, will display the product on all available supported application>"
      defaultProducts="<optional, a stringified key vale pair, key: application, value: product sku, will present those as defaults >"
    ></div>
    <script>
      const containerElement = document.querySelector('[data-role="visualizer"]')
      containerElement.addEventListener('visualizerLoaded', (event) => {
        const visualizer = event.detail.visualizer
      })
    </script>
    <script src="https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/index.js"></script>
  </body>
</html>
```

## Customization, Theming Supported & css variables

It can be given as a configuration linked to the experienceId
Otherwise as a HTML and CSS as in the examples bellow..

To override a css rules add a css file like in the example
<https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/examples/globalVariables.css>

### Changing constant titles labels and icons

pass a stringified object as an attribute into the base div element

#### example

```html
<body>
  <div
    class="visualizer"
    data-role="visualizer"
    experienceId="<your experience id here>"
    constants='{"menu":{"hotspots":{"label":"Hotspots"}}}'
  ></div>
</body>
```

#### a full Documentation of custom labels titles and icons can be found under the Constants section

<https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/doc/modules/src_app_iconstants.html>"

#### an example for a constant object can be found at

<https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/examples/Constants.json>"

### Client API

It is accessed through an object that is attached to the visualizer container:

```js
const container = document.querySelector('[data-role="visualizer"]')
container.visualizerUI.showAddToCart('sku')
```

Documentation of the methods available on that object:
<https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/doc/modules/src_app_clientapitypes.html>

## Launcher

Documentation:
<https://visualizer.byondxr.com/releases/visualizer-ui/3.0.98/doc/modules/generated_doc_launchertypes.html>

```ts
export type IFavoriteScene = {
    id: string;
    image: string;
    favorites: IFavorite[];
    scene: IScene;
};
export type IFavoriteSceneList = IFavoriteScene[];

export type IProduct = {
    sku: string;
    name?: string;
    title: string;
    description?: string;
    application: string;
    image: string;
    price?: string;
    facets?: IFacet[];
    badges?: string[];
    applications?: string[];
    _id: string;
};
export type IFavorite = {
    product: IProduct;
};
export type IFavoriteProductList = IFavorite[];

export type IProductSkuAndApplication = {
    sku: string;
    application: string;
};
export type IFavoriteProductSkuAndApplication = {
    product: IProductSkuAndApplication;
};
export type IFavoriteProductSkuAndApplicationList = IFavoriteProductSkuAndApplication[];


type TLaunchParam = {
    selector?: string
    sceneId?: string
    defaultApplication?: string
    defaultProduct?: string | number
    scene_configuration?: string
    experienceId?: string
    hashExperienceId?: string
    maxProductMapSize?: string | number
    maxProductMapSizeMobile?: string | number
    maxMapSize?: string | number
    maxMapSizeMobile?: string | number
    defaultProducts?: { [index: string]: string | number }
    productsList?: (string | number)[]
    favoriteScenes?: IFavoriteSceneList
    favoriteProducts?:  IFavoriteProductList | IFavoriteProductSkuAndApplicationList
}

type TVisualizerContainer: Element

window.launchVisualizer(params: TLaunchParams): Promise<TVisualizerContainer>
```

### Launcher example

```html
        <button
            onClick={() => {
                window.launchVisualizer({
                    experienceId: 'G2GcP2',
                    defaultProducts: { Countertop: '1200302000' },
                    defaultProduct: '1200302000',
                    productsList: ['1200302000', '334442000']
                    sceneId: '6',
                    scene_configuration: 'US-EN',
                }).then((visualizerContainer)=>{
                    // Here the visualizer is loaded and you can do with it whatever you need such as:
                    visualizerContainer.visualizerUI.showAddToCart('sku')
                    visualizerContainer.visualizer.setFavoriteProducts([ {product: {application: 'Backsplash', sku: '1040502005'}} ])
                })
            }}
        >
            Launch
        </button>
```

## Favorites

```ts
    /** set favorite scenes */
    abstract setFavoriteScenes(favoriteScenes: IFavoriteSceneList);

    /** set favorite products */
    abstract setFavoriteProducts(favoriteProducts: IFavoriteProductList | IFavoriteProductShortList);

```

**Code example:**

```ts
// subscribe to events that save favorites to localstorage
let subscribe = (container) => {
  const saveProducts = (param) => {
    localStorage.setItem('favoriteProducts', JSON.stringify(param.favorites))
  }
  const saveScenes = (param) => {
    localStorage.setItem('favoriteScenes', JSON.stringify(param.favoriteScenes))
  }
  container.Visualizer.addListener('productAddedToFavorites', saveProducts)
  container.Visualizer.addListener('productRemovedFromFavorites', saveProducts)
  container.Visualizer.addListener('sceneAddedToFavorites', saveScenes)
  container.Visualizer.addListener('sceneRemovedFromFavorites', saveScenes)

  // upon new start of application - read from localstorage
  container.Visualizer.setFavoriteProducts(JSON.parse(localStorage.getItem('favoriteProducts')))
  container.Visualizer.setFavoriteScenes(JSON.parse(localStorage.getItem('favoriteScenes')))
}
```

Subscribe to the Visualizer by acquiring its container. Example:

```ts
container = document.querySelector('[data-role="visualizer"]')
subscribe(container)
```

If the container is not there beause it will be launched, then use the launchVisualizer promise to acquire the container

```html
        <button onclick="
            const productsInitExampleSkus = ()=> {
                const products = [   {product: {application: 'Backsplash', sku: '1040502005'}},
                        {product: {application: 'Countertop', sku: '1400402005'}},
                        {product: {application: 'Countertop', sku: '1401102015'}},
                        {product: {application: 'Countertop', sku: '1400302005'}} ]
                localStorage.setItem('favoriteProducts', JSON.stringify(products))
            }

            productsInitExampleSkus()

        ">
            example - saves favorite product sku/application pairs to localstorage
        </button>
        <button
            onClick={() => {
                window.launchVisualizer({
                    experienceId: 'G2GcP2',
                    defaultProducts: { Countertop: '1200302000' },
                    defaultProduct: '1200302000',
                    sceneId: '6',
                    scene_configuration: 'US-EN',
                }).then((visualizerContainer)=>{
                    // Here the visualizer is loaded and you can do with it whatever you need
                    subscribe(visualizerContainer)
                })
            }}
        >
            Launch
        </button>
```

## Badges

### Badges look

- the badges are absolute pusition relative to the image of the product

```ts
"theme": {
  "catalogBadges": {
        "badgeField": "__FilterSize",
        "badges": [
          {
            "name": "new",
            "label": "New",
            "bgcolor": "red",
            "icon": {
              "url": "https://web-apps.byondxr.com/assets/alony/icons/photo-camera.svg"
            }
          },
          {
            "style": {
              "right": "0",
              "left": "auto",
              "borderRadius": "3px 0px 0px 3px"
            },
            "name": "sale",
            "label": "30% SALE",
            "bgcolor": "C58"
          }
        ]
     }
}
```

### First option

Definitions (badges) are read from the catalog custom fields.

### Second option

Badges are provided on client .
First client will receive event: 'productsListed' with this eventData: { detail: { products: { sku: string }[] } }
Then, on his own time, he will call client-api function provided with badges:

```ts
const elm = document.querySelector('[data-role="visualizer"]')
elm.addEventListener('productsListed', (event) => {
  let products = event.detail.products
  console.log(products)
  products[0].badges = ['sale']
  products[1].badges = ['new']
  elm.visualizerUI.setProductsBadges({ products })
})
```

```ts
export type TSetProductsBadgesParams = {
    products: {
        sku: string
        badges: string[]
    }[]
}

setProductsBadges: (params: TSetProductsBadgesParams) => void
```

## Product details dialog

### Additional Product fields

detailsText:

- it will show in the dialog as an additonal text
- this name is not final, is just an example (till then, the string shows just an example )

### Theme settings

- Modify launch button text and visibility (which is always add-to-cart)
- Modify product details dialog button

```json
{
  "theme": {
    "buttons": {
      "add_to_cart": {
        "label": "More Details",
        "visible": true
      },
      "productDetails": {
        "add_to_cart": {
          "label": "Add to cart",
          "visible": true
        }
      }
    }
  }
}
```

### Per application settings in the publisher config

- existense of productDetails config
  under application object as bellow - will enable the Launch button to open the dialog

#### PD example

```json
{
  "applications": [
    {
      "application": "application-name",
      "productDetails": {
        "model": {
          "edges": [
            {
              "imageUrl": "https://i.ibb.co/bX6N02D/edge1.png",
              "label": "edgeccccc text 1 QA TEST",
              "animationName": "",
              "id": "edge1"
            },
            {
              "imageUrl": "https://i.ibb.co/bX6N02D/edge1.png",
              "label": "edge text 2",
              "animationName": "CT 02",
              "id": "edge2"
            },
            {
              "imageUrl": "https://i.ibb.co/bgZmztN/edge2.png",
              "label": "edge text 3",
              "animationName": "CT 03",
              "id": "edge3"
            }
          ],
          "modelUrl": "https://drive.google.com/uc?export=download&id=1z2LzIw_iJuif2huNdFxCRskR_HzIDZVC",
          "distance": "4.1",
          "yRotate": "60",
          "xRotate": "50"
        },
        "fields": {
          "detailsText": {
            "visible": true
          },
          "description": {
            "visible": true
          },
          "price": {
            "visible": true
          },
          "title": {
            "visible": true
          }
        },
        "buttons": {
          "addToCart": {
            "visible": true
          }
        }
      }
    }
  ]
}
```

#### PD Types

```ts
export interface IButtonConfiguration {
  visible?: boolean
}
export interface IFieldConfiguration {
  visible?: boolean
}
export interface IProductDetailsButtonsConfiguration {
  addToCart?: IButtonConfiguration
}

export interface IProductDetailsFieldsConfiguration {
  price?: IFieldConfiguration
  title?: IFieldConfiguration
  description?: IFieldConfiguration
  detailsText?: IFieldConfiguration
}
export interface IProductDetailsEdgeConfiguration {
  id: string
  animationName: string
  label: string
  imageUrl: string
}

export interface IProductDetailsModelConfiguration {
  modelUrl: string
  xRotate?: number
  yRotate?: number
  distance?: number
  edges: IProductDetailsEdgeConfiguration[]
}

export interface IProductDetails {
  buttons?: IProductDetailsButtonsConfiguration
  fields?: IProductDetailsFieldsConfiguration
  model: IProductDetailsModelConfiguration
}

export interface IApplication {
  application: string
  title: string
  image?: string
  productDetails?: IProductDetails
  buttons?: IApplicationButtonsConfiguration
  fields?: IApplicationFieldsConfiguration
}
```

### Sorting of products according to specific custom field value

config:

```json
{
  "products": {
    "order": {
      "field": "custom field name"
    }
  }
}
```

The value of this custom field will be numeric and according to this value the products will be sorted. Otherwise the default is to sort products by title ascending
