npm package: @opensolar/ossdk-react
Description: React bindings for the OpenSolar SDK (OsSdk)
Latest version: 0.8.2


# ossdk-react

React bindings for the OpenSolar SDK (OsSdk).

[![NPM](https://img.shields.io/npm/v/@opensolar/ossdk-react.svg)](https://www.npmjs.com/package/@opensolar/ossdk-react)


## Install

Use the following command to install:

```bash
npm install --save @opensolar/ossdk-react
```

#### Migrating from `ossdk-react`

If you are migration from `ossdk-react` you can find instructions below. The package `ossdk-react` is deprecated in favour of this package. 

1. Update `package.json`: change the dependency from `ossdk-react` to `@opensolar/ossdk-react`
2. Update imports: change imports from `import OsSdkView from 'ossdk-react'` to `import OsSdkView from '@opensolar/ossdk-react'`


## OsSdkView

The key component to embed the OpenSolar SDK within your app is `OsSdkView`. 

## Example usage

```jsx
import React, { Component } from 'react'

import OsSdkView from '@opensolar/ossdk-react'

class Example extends Component {
  render() {
    return (
      <OsSdkView
        key={'unique-identifier-within-page'}
        osToken={'Token or empty if using SSO'}
        osScriptLocation={'https://app.opensolar.com/sdk/v1.0/min.js'}
        osSdkKey={'my-sdk-key'}
        projectData={[{identifier: '123-main-st-uuid'}]}
        projectIdentifiersToken={'xyz'}
        onLoad={(ossdk) => {
          clearSignalHandlers(ossdk);
          ossdk.studio.objectSelected.add((object) => {
            console.log("objectSelected", object);
          });
        }}
        onRemove={(ossdk) => {
          clearSignalHandlers(ossdk);
        }}
      />
    )
  }
}

```

## OsSdkView Component Props

- **osSdkKey**: (string, requried): Key supplied by OpenSolar. Required in order to use the SDK.
- **key**: (string, required): Unique key used by React which is used to control when the component should be reloaded. Value should be unique within the React context.
- **height**: (number, optional) Height of the component, in pixels. Defaults to 600px. Note: Width is always 100% of the container width.
- **toolbar**: (ReactElement, optional): Toolbar to display at the top of the OsSdkView.
- **osToken**: (string, optional): OsSdk token which has been securely generated using an OsSdk Signing Key. Used for authentication against SDK. Leave this out if using SSO.
- **projectIdentifiersToken**: (string, optional):  Additional token, only used to grant additional project access permissions when using SalesForce SSO. When authenticating with OsSdk Tokens the project permissions should be added there, and projectIdentifiersToken should be omitted.
- **osScriptLocation**: (string, required): URL to the SDK script. Set based on target environment which will be provided as appropriate. Usually: https://api.opensolar.com/sdk/v1.0/min.js
- **projectData**: (object, required): Dictionary containing data that is used to initialize the design (and can be used to update the same properties when returning to an existing design). Including:
  - Required fields:
    - identifier (string, unique, required): Unique identifier of the project.
    - lon (float, required): Used to start design at correct location
    - lat (float, required): See lon.
  - Optional fields:
    - address (string, optional)
    - locality (string, optional)
    - state (string, optional): 2-letter state.
    - zip (string, optional)
    - country_iso2  (string, optional): 2-letter Country ISO.
- **sdkConfig**: (object, required if using SSO): Configuration options passed to the SDK. Options include:
  - `view_overrides`: Customize UI elements including showing/hiding. [See below for available options](#view-overrides).
  - `login_configs_override`: SSO Configuration. Only available in localhost during development. For online/production use this must be configured by OpenSolar and associated with the `osSdkKey` value, see above. Contact OpenSolar Support to setup.
- **extraScriptParams**: (string, *deprecated*): Options for configuring the SDK, as a query that can be appended to a URL. Supports the same config variables as `sdkConfig` but is deprecated in favor of `sdkConfig`.
- **onMessage**: (function, optional): Handler for showing messages generated by OsSdk in your container app. message.severity can be: `success`, `error`, `debug`. Example:
  ```javascript
  onMessage={(message, err) => {
    let messageText = message.text + (err && err?.message ? ": " + err.message : "");
    if (message.severity !== "debug") {
      yourShowAlertMessage(messageText, message.severity);
    }
    if (err) console.warn(err);
  }}
  ```
- **onLoad**: (function, optional): Handler which fires after ossdk is initialized. Add handlers so your app can respond to events generated by OsSdk. See below for all available methods. Example:
  ```javascript
  // In the example below, the following functions are defined by your app:
  // - setCurrentRole
  // - setHasUnsavedChanges
  // - setSelected
  // - setSystem

  onLoad={(ossdk) => {
    // Clear signal handlers first to ensure that there are no lingering handlers from a previous sdk instance.
    // Sometimes they may not cleanup handlers if they do not exit as expected, e.g. when the iframe is removed
    // rather than simply removing the sdk react component.
    clearSignalHandlers(ossdk)

    ossdk.current_org.id.add((state) => { setOrgId(state); }, { now: true })

    ossdk.auth.current_role.add((state) => { setCurrentRole(state); }, { now: true })

    ossdk.project_form.dirty_fields.add((state) => { setHasUnsavedChanges(state.length > 0); }, { now: true })

    ossdk.studio.objectSelected.add((object) => {
      setSelected(object)
      if (object?.type === "OsSystem") { setSystem(object) }
    });

    ossdk.studio.objectAdded.add((object) => { console.log("objectAdded", object) });

    ossdk.studio.objectChanged.add((object, attributeName) => {
      if (object?.type === "OsSystem") { setSystem(object) }
    })

    ossdk.studio.objectRemoved.add((object) => { console.log("objectRemoved", object) })

    ossdk.studio.sceneLoaded.add(() => {setIsStudioReady(true) })

    ossdk.studio.queueProcessed.add((progress) => { setProgress(progress)} )
  }}
  ```
- **onRemove**: (function, optional): Clean up and remove handlers when component is removed from the DOM. Sample:
  ```javascript
  onRemove={(ossdk) => {
    clearSignalHandlers(ossdk);
  }}
  ```

## <a name="sdk-instance-methods"></a>Reference: OsSdk Instance Methods

### Index of methods:

- auth

  - ossdk.auth.current_role
  - ossdk.auth.logout
  - [ossdk.auth.refreshToken](#ossdk-auth-refreshtoken)
  - ossdk.auth.setProjectIdentifiersToken

- current_org
  - [ossdk.current_org.id](#ossdk-current-org-id)

- flows
  - ossdk.flows.createOrUpdateProject
  - ossdk.flows.generateDocument

- project_form
  - ossdk.project_form.active
  - [ossdk.project_form.discard](#ossdk-project_form-discard)
  - ossdk.project_form.dirty_fields
  - [ossdk.project_form.getDesignData](#ossdk-project_form-getdesigndata)
  - [ossdk.project_form.save](#ossdk-project_form-save)
  - ossdk.project_form.save_state
  - ossdk.project_form.save_state.value
  - ossdk.project_form.system_count.value
  - ossdk.project_form.system_summaries.value
  - ossdk.project_form.setValues
  - [ossdk.project_form.values](#ossdk-project_form-values)

- resources
  - ossdk.resources.projects

- route
  - ossdk.route.goto
  - ossdk.route.path
  - ossdk.route.path.value
  - ossdk.route.route.add
  - ossdk.route.route
  - ossdk.route.route.remove
  - ossdk.route.route.value

- studio
  - ossdk.studio.callFunction
  - ossdk.studio.executeCommand
  - ossdk.studio.getLoadedData
  - ossdk.studio.getSelectedSystemData
  - ossdk.studio.getSystemImageUrl
  - [ossdk.studio.setComponents](#ossdk-studio-setcomponents)
  - ossdk.studio.autoDesignRunAndLoadFromEquipment
  - ossdk.studio.objectSelected
  - ossdk.studio.objectAdded
  - ossdk.studio.objectChanged
  - ossdk.studio.objectRemoved
  - ossdk.studio.sceneLoaded
  - [ossdk.studio.queueProcessed](#ossdk-studio-queueprocessed)

### <a name="ossdk-auth-refreshtoken"></a>Refresh Token (Action)

```javascript
const { loaded, ossdk } = useOsSdk();
ossdk.auth.refreshToken(newToken);
```

### <a name="ossdk-current-org-id"></a>Current Org Id (State)

```javascript
// setOrgId is defined by your Container App
onLoad={(ossdk) => {
  ossdk.current_org.id.add((state) => { setOrgId(state) }, { now: true })
})
```

### <a name="ossdk-project_form-save"></a>Save Design (Action)

Save Design to OpenSolar Database

```javascript
ossdk.project_form
    .save()
    .then(() => console.log("Project saved"))
    .catch((e) => console.error("Failed to save project", e))
```

### <a name="ossdk-project_form-discard"></a>Discard Design (Action)

Discard changes and revert to design from database.

```javascript
ossdk.project_form
    .discard()
    .then(() => console.log("Project discarded"))
    .catch((e) => console.error("Failed to discard project", e))
```

### <a name="ossdk-studio-setcomponents"></a>Set Components (Action)

Set hardware explicitly for the current system. Note: "Panel" type hardware can be set here but still need to be placed manually.

Arguments:

- `components: { code: string, quantity?: number }[]`. Components and quantities to add.
- `keepExistingComponents?: Boolean` (optional, default: false). By default this will clear all components of the current system before adding the specified components.
- `systemUuid?: string`. Optionally update a specific system. If omitted it will update the currently selected system.

```javascript
ossdk.studio.setComponents([
    { code: "Q.PEAK DUO BLK ML-G10+ 400" },
    { code: "IQ6-60-2-INT" },
    { code: "Tesla Powerwall 2.0" },
    { code: "ENV-S-WM-230", quantity: 4 },
])
```

### <a name="ossdk-studio-queueprocessed"></a>QueueProcessed (Signal)

Handling queueProcessed signals:

```javascript
ossdk.studio.queueProcessed.add((progress) => {
  console.log(progress)
} )
```

Sample `progress` payload:

```javascript
{

  // list of system uuids with calcs in progress
  systemCalcsInProgressUuids: ['abc','def'],

  // scene is loading
  sceneLoadingInProgress: false,
  
  // any views are loading including any 3D data loading
  viewsLoadingInProgress: false,

  // any system calcs are awaiting or in progress
  systemCalcsInProgress: false,

  // auto-design is in progress
  autoDesignEphemeralInProgress:false,

  // any full calcs are in progress
  fullCalcsInProgress: false,

  // false if any other work is in progress except for fullCalcsInProgress
  // because this is not handled by studio in the front-end, it is a separate
  // background/back-end process that is relevant to track but not actually
  // something being "done" in studio.
  idle: true
}
```

### <a name="ossdk-project_form-values"></a>Get Project Field Values (State)

Get fields on the OS "Project" record such as: id, address, zip, state, country_iso2, lon, lat

```javascript
console.log(ossdk.project_form.values.address)
```

### <a name="ossdk-project_form-getdesigndata"></a>Get Design Data (Action)

Design data as JSON, including all aspects of designs, shading simulations & calculations. e.g.

- Annual output can be accessed at `designData.object.children[0].userData.output.annual`
- Panel quantity at `designData.object.children[0].userData.moduleQuantity`

```javascript
ossdk.project_form.getDesignData().then((designData) => {
    console.log(designData)
})
```

## <a name="view-overrides"></a>Reference: Available view_overrides

```javascript
const view_overrides = {
  "header": { "show": true },
  "homepage": { "show": true },
  "forms.project.header": { "show": true },
  "forms.project.save_status": { "show": true },
  "studio.systems": { "show": true },
  "studio.tab_panels.summary": { "show": true },
  "studio.systems.overview": { "show": true },
  "studio.tabs.panels.add": { "show": true },
  "studio.systems.add_new_system": { "show": true },
  "studio.systems.duplicate_system": { "show": true },
  "studio.tabs.summary": { "show": true },
  "studio.tabs.panels": { "show": true },
  "studio.tabs.panels.select_panel_type": { "show": true },
  "studio.tabs.panels.buildable_panels": { "show": true },
  "studio.tabs.panels.select_dc_optimizer": { "show": true },

  "studio.tabs.selected_panel_group.basic_settings": { "show": true },
  "studio.tabs.selected_panel_group.advanced_settings": { "show": true },
  "studio.tabs.selected_panel_group.shading": { "show": true },
  "studio.tabs.selected_panel_group.buildable_panels": { "show": true },
  "studio.tabs.selected_panel_group.tools": { "show": true },

  "studio.tabs.selected_panel_group.tools.FillRectangle": { "show": true },
  "studio.tabs.selected_panel_group.tools.FillFacet": { "show": true },
  "studio.tabs.selected_panel_group.tools.SelectFacet": { "show": true },
  "studio.tabs.selected_panel_group.tools.Duplicate": { "show": true },
  "studio.tabs.selected_panel_group.tools.AutoString": { "show": true },
  "studio.tabs.selected_panel_group.tools.Delete": { "show": true },

  "studio.tabs.mounting": { "show": true },
  "studio.tabs.inverters": { "show": true },
  "studio.tabs.batteries": { "show": true },
  "studio.tabs.others": { "show": true },
  "studio.tabs.pricing": { "show": true },
  "studio.tabs.payment_options": { "show": true },
  "studio.tabs.scaffolding": { "show": true },
  "studio.tabs.incentives": { "show": true },

  "studio.select_design_mode": { "show": true },
  "studio.select_design_mode.2D": { "show": true },
  "studio.select_design_mode.3D": { "show": true },
  "studio.select_design_mode.Manual": { "show": true },
  "studio.advanced": { "show": true },
  "studio.advanced.DesignGuides": { "show": true },
  "studio.advanced.Restart": { "show": true },
  "studio.advanced.Recalculate": { "show": true },
  "studio.advanced.DownloadDxf": { "show": true },

  "studio.view_controls": { "show": true },
  "studio.view_controls.ViewShadeButton": { "show": true },
  "studio.view_controls.AlignMapButton": { "show": true },
  "studio.view_controls.StreetViewButton": { "show": true },
  "studio.view_controls.ZoomOutButton": { "show": true },
  "studio.view_controls.ZoomInButton": { "show": true },
  "studio.view_controls.MeasureHeightButton": { "show": true },
  "studio.view_controls.DownloadSnapshotsButton": { "show": true },

  "studio.view_selector": { "show": true }
}
```