npm package: @haravan/app-sdk
Description: app-sdk
Author: Haravan Inc.
Latest version: 1.5.1449159

## Installation

You can install Haravan App SDK by using [Nmp](https://www.npmjs.com) or [Yarn](https://yarnpkg.com):

``` sh
npm install --save @haravan/app-sdk
```

or

``` sh
yarn add @haravan/app-sdk
```

Haravan App SDK can also be included directly on a page with a script tag pointing to a CDN-hosted copy of the library.  [Unpkg](https://unpkg.com/) is an example of a CDN that hosts npm modules.

``` html
<script src="https://unpkg.com/@haravan/app-sdk"></script>
<script>
  var AppSDK = window['app-sdk'];
  var actions = AppSDK.actions;
  var createApp = AppSDK.createApp;
</script>
```


## Usage

### Initializing Haravan App SDK

In the following example, you need to store `shopOrigin` during the authentication process and then retrieve it for the code to work properly.

Import the library from the `@haravan/app-sdk` package and provide a configuration:

``` ts
import createApp from '@haravan/app-sdk';

const app = createApp({
  apiKey: 'Client ID from Haravan App Setting',
  shopOrigin: shopOrigin,   // "shopname.myharavan.com"
  embedded: true
});
```

Using ES5 and the CDN-hosted version:
``` js
var AppSDK = window['app-sdk'];
var createApp = AppSDK.createApp;
var app = createApp({
  apiKey: 'Client ID from Haravan App Setting',
  shopOrigin: shopOrigin,  // "shopname.myharavan.com"
  embedded: true
});
```

var redirectAdminUrl = "https://" + shopOrigin + "/admin/apps/"  + apiKey;

embedded: auto redirect to redirectAdminUrl if app not in iframe. set embedded=false to handle redirect manually.


## Actions

Haravan App SDK introduces the concept of actions. An action provides a way for applications and hosts to trigger events with a statically-typed payload.

### Redirect

The Redirect action set allows you to modify the top-level browser URL. Use the Redirect action set to navigate within your app, or to redirect merchants else where within the Haravan admin , or redirect to accounts.haravan.com for Install App.

The following REMOTE domains are allowed:
  1. Redirect Url declared in app setting
  2. Redirect Url to accounts.haravan.com

``` js
import {createApp, actions} from '@haravan/app-sdk';
const Redirect = actions.Redirect;
const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});
const redirect = Redirect.create(app);

//Redirect to accounts.haravan.com
redirect.dispatch(Redirect.Action.REMOTE, "https://accounts.haravan.com");

//Redirect to accounts.haravan.com with newContext (open new tab)
redirect.dispatch(Redirect.Action.REMOTE, {
    url: "https://accounts.haravan.com",
    newContext: true,
});

//Redirect to a relative path in Haravan admin

//Go to {shopUrl}/admin/customers
redirect.dispatch(Redirect.Action.ADMIN_PATH, '/customers');

//Go to {shopUrl}/admin/customers with newContext (open new tab)
redirect.dispatch(Redirect.Action.ADMIN_PATH, {
   path: '/customers',
   newContext: true,
});

//Redirect to a named section in Haravan admin
//Section: products, collections, orders, customers, discounts

//Redirect to the Products section in the Haravan admin:
//Go to {shopUrl}/admin/products
redirect.dispatch(Redirect.Action.ADMIN_SECTION, {
   name: Redirect.ResourceType.Product,
});
//or with newContext (open new tab)
redirect.dispatch(Redirect.Action.ADMIN_SECTION, {
   section: {
     name: Redirect.ResourceType.Product,
   },
   newContext: true,
});

//Redirect to a specific resource in Haravan admin.
//Redirect to the collection with the ID 123 in the Haravan admin:
//Go to {shopUrl}/admin/collections/123
redirect.dispatch(Redirect.Action.ADMIN_SECTION, {
  name: Redirect.ResourceType.Collection,
  resource: {
    id: '123',
  },
});

//Redirect to create a product in Haravan admin.
//Redirect to {shopUrl}/admin/products/new in the Haravan admin:
//Go to {shopUrl}/admin/products/new
redirect.dispatch(Redirect.Action.ADMIN_SECTION, {
  name: Redirect.ResourceType.Product,
  resource: {
    create: true,
  },
});

//Redirect to a product variant in Haravan admin.
//Go to {shopUrl}/admin/products/123/variant/456
redirect.dispatch(Redirect.Action.ADMIN_SECTION, {
  name: Redirect.ResourceType.Product,
  resource: {
    id: '123',
    variant: {
      id: '456',
    },
  },
});
```

_________________
### Toast
The Toast action set displays a non-disruptive message that appears at the bottom of the interface to provide quick and short feedback on the outcome of an action.

Use Toast to convey general confirmation for actions that aren’t critical. For example, you might show a toast message to inform the merchant that their recent action was successful.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var Toast = actions.Toast;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});

//Create a toast notice
const toastOptions = {
    message: 'Product saved',
    duration: 5000,
};
const toastNotice = Toast.create(app, toastOptions);
toastNotice.dispatch(Toast.Action.SHOW);

//Create a toast error message
const toastOptions = {
    message: 'Error saving',
    duration: 5000,
    isError: true,
};
const toastError = Toast.create(app, toastOptions);
toastError.dispatch(Toast.Action.SHOW);
```
_________________
### Loading

The loading action set is used to indicate to merchants that a page is loading or an upload is processing.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var Loading = actions.Loading;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});
const loading = Loading.create(app);

//Start loading
loading.dispatch(Loading.Action.START);

//Stop loading
loading.dispatch(Loading.Action.STOP);
```
_________________
### SessionToken

Return a Promise of session token used by Embedded Authorization

``` js
import {createApp, actions} from '@haravan/app-sdk';
var SessionToken = actions.SessionToken;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});

SessionToken.getSessionToken(app)
    .then(newToken => console.log(newToken))
    .catch(err => {
        if(actions.Error.Action.FAILED_AUTHENTICATION === err.type){
            console.log(err.type);
            //should redirect to redirectAdminUrl
        }
        if(actions.Error.Action.NOT_FOUND === err.type){
            console.log(err.type);
            //should redirect to installUrl
        }
        console.log(err);
    });

```

A session token, also known as a JWT (JSON web token), lets your app authenticate the requests that it makes between the client side and your app's backend. It also contains information about the merchant who's logged in to the Haravan admin.

This session token only use to verify user, it can't use to call api.

Verify the Session token: do it only in Backend server

``` js
$ npm install jsonwebtoken -save
```

``` js
var jwt = require('jsonwebtoken');
let options = {
  algorithms: "HS256",
  clockTolerance: 10 //number of seconds to tolerate when checking the nbf and exp claims, to deal with small clock differences among different servers
}
let clientSecret = "b4c69...2570"; //Your App Client Secret
let newToken = "eyJh...Dr3k";   //Your new SessionToken

jwt.verify(newToken, clientSecret, options, function(err, decoded) {
  console.log(err);
  console.log(JSON.stringify(decoded));
});
```

### Validate

Determine if App not in iframe.

``` js
import {actions} from '@haravan/app-sdk';

if(actions.isAppNotInIframe()){
  console.log("Not in iframe");
}else{
  console.log("In iframe");
}
```
_________________
### History

The History action set allows you to use the JavaScript History API to modify the top-level browser URL without navigating. Use the History action set to update the top-level browser URL to match your app. The path is relative to the app origin and must be prefixed with a slash.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var History = actions.History;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});
const history = History.create(app);

// Pushes {appOrigin}/settings to the history
history.dispatch(History.Action.PUSH, '/settings');

// Replaces the current history url with {appOrigin}/settings
history.dispatch(History.Action.REPLACE, '/settings');
```
_________________
### Fullscreen

The Fullscreen action hides Haravan UI and expands the application iframe to cover the entirety of the browser window. This gives applications the ability to implement complex workflows such as editing workflows, immersive experiences, or previews.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var Fullscreen = actions.Fullscreen;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});
const fullscreen = Fullscreen.create(app);

// Call the `ENTER` action to put the app in full-screen mode
fullscreen.dispatch(Fullscreen.Action.ENTER);

// Call the `EXIT` action to take the app out of full-screen mode
fullscreen.dispatch(Fullscreen.Action.EXIT);
```
_________________
### Contextual Save Bar

Display the contextual save bar to indicate that a form on the current page contains unsaved information, or when the merchant is in the process of creating a new object, such as a product or customer. The contextual save bar provides save and discard buttons to a merchant.

**Props**: The ContextualSaveBar component accepts the following props
| Name      | Type | Description | Required |
| ----------- | ----------- |----------- |----------- |
| saveAction  | SaveActionOptions | Options to customize save behaviour | No |
| discardAction | DiscardActionOptions | Options to customize discard behaviour | No |
| fullWidth  | boolean | Whether the contextual save bar should fill the entire screen width | No |
| leaveConfirmationDisable  | boolean | Whether to show a confirmation modal after the user navigates away from the page | No |
<br>

**SaveActionOptions**

| Name      | Type | Description | Required |
| ----------- | ----------- |----------- |----------- |
| disabled  | boolean | Whether the contextual save bar button is in a disabled state | No |
| loading  | boolean | Whether the contextual save bar button is in a loading state | No |
<br>

**DiscardActionOptions**

| Name      | Type | Description | Required |
| ----------- | ----------- |----------- |----------- |
| disabled  | boolean | Whether the contextual discard bar button is in a disabled state | No |
| loading  | boolean | Whether the contextual discard bar button is in a loading state | No |
| discardConfirmationModal  | boolean | Whether to show a confirmation modal after the user clicks the Discard button of the contextual save bar | No |
<br>

``` js
import {createApp, actions} from '@haravan/app-sdk';
var ContextualSaveBar = actions.ContextualSaveBar;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: true
});
const contextualSaveBar = ContextualSaveBar.create(app, {
    saveAction: {
        disabled: false,
        loading: false,
    },
    discardAction: {
        disabled: false,
        loading: false,
        discardConfirmationModal: true,
    },
    fullWidth:false,
    leaveConfirmationDisable: false
});

//SHOW
contextualSaveBar.dispatch(ContextualSaveBar.Action.SHOW);

//Hide
contextualSaveBar.dispatch(ContextualSaveBar.Action.HIDE);

//Update options
//You can modify the options at any time using the set method. If the contextual save bar is visible, the UI will update immediately.
contextualSaveBar.set({fullWidth:true});
contextualSaveBar.set({leaveConfirmationDisable:true});
contextualSaveBar.set({saveAction: {disabled: true}});
contextualSaveBar.set({saveAction: {disabled: false}});
contextualSaveBar.set({saveAction: {loading: true}});
contextualSaveBar.set({saveAction: {loading: false}});
contextualSaveBar.set({discardAction: {disabled: true}});
contextualSaveBar.set({discardAction: {disabled: false}});
contextualSaveBar.set({discardAction: {loading: true}});
contextualSaveBar.set({discardAction: {loading: false}});
contextualSaveBar.set({discardAction: {discardConfirmationModal: true}});
contextualSaveBar.set({discardAction: {discardConfirmationModal: false}});
```

### Subscribe to Discard and Save

Subscribe to the contextual save bar actions (ContextualSaveBar.Action.DISCARD and ContextualSaveBar.Action.SAVE) in order to do something when a merchant clicks the Save or Discard button. The subscribe method returns a function that you can call to unsubscribe from the action.

To hide the contextual save bar, dispatch a ContextualSaveBar.Action.HIDE action in the subscribe callback.

``` js
const discardUnsubscribe = contextualSaveBar.subscribe(
  ContextualSaveBar.Action.DISCARD,
  function() {
    // Hide the contextual save bar
    contextualSaveBar.dispatch(ContextualSaveBar.Action.HIDE);
    // Do something with the discard action
  }
);
const saveUnsubscribe = contextualSaveBar.subscribe(
  ContextualSaveBar.Action.SAVE,
  function() {
    // Optionally, show a loading spinner while the save action is in progress
    contextualSaveBar.set({saveAction: {loading: true}});
    await doSaveAction();

    // Hide the contextual save bar
    contextualSaveBar.dispatch(ContextualSaveBar.Action.HIDE);
  }
);
// Unsubscribe
discardUnsubscribe();
saveUnsubscribe();
```

### Unsubscribe
Call the unsubscribe method to remove all current subscriptions on the contextual save bar.

``` js
contextualSaveBar.subscribe(ContextualSaveBar.Action.DISCARD, function () {
  // Do something with the discard action
  // Hide the contextual save bar
  contextualSaveBar.dispatch(ContextualSaveBar.Action.HIDE);
});

contextualSaveBar.subscribe(ContextualSaveBar.Action.SAVE, function () {
  // Do something with the save action
  // Hide the contextual save bar
  contextualSaveBar.dispatch(ContextualSaveBar.Action.HIDE);
});

// Unsubscribe
contextualSaveBar.unsubscribe();
```

_________________
### Frame

The frame action set is used to let the main window know that the iframe page has been initialized.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var Frame = actions.Frame;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: false
});
const frame = Frame.create(app);

frame.dispatch(Frame.Action.INITIALIZED);
```

_________________
### Navigation Menu

The NavigationMenu component creates a navigation menu for your app. On desktop web browsers, the navigation menu appears as part of the app nav, on the left of the screen.

``` js
import {createApp, actions} from '@haravan/app-sdk';
var AppLink = actions.AppLink;
var NavigationMenu = actions.NavigationMenu;

const app = createApp({
  apiKey: '77d6...ea14',
  shopOrigin: "shopname.myharavan.com",
  embedded: false
});

const itemsLink = AppLink.create(app, {
  label: 'Items',
  destination: '/items',
});

const settingsLink = AppLink.create(app, {
  label: 'Settings',
  destination: '/settings',
});

// create NavigationMenu with no active links
const navigationMenu = NavigationMenu.create(app, {
  items: [itemsLink, settingsLink],
});

// or create a NavigationMenu with the settings link active
const navigationMenu = NavigationMenu.create(app, {
  items: [itemsLink, settingsLink],
  active: settingsLink,
});

//Set an active nav item
navigationMenu.set({active: itemsLink});

//Reset active nav item
navigationMenu.set({active: undefined});
```