> ## Documentation Index
> Fetch the complete documentation index at: https://sidedish.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Embedding a component

> How to include an embeddable component in your app

<Note>
  All the following examples are for a `Store Page` but are applicable to any embeddable component.
</Note>

## Embedding using a prebuilt React component

### Basic usage

We also provide the `@sidedish/react` package that you can use to easily embed your store. To use it, simply run:

<CodeGroup>
  ```bash npm 
  npm install @sidedish/react 
  ```

  ```bash yarn 
  yarn add @sidedish/react 
  ```
</CodeGroup>

The npm package is super lightweight. To use it, simply provide store url and optional sessionId.

```tsx
import { StorePage } from '@sidedish/react';

const StoreEmbed = () => {
const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables
return <StorePage url={STORE_PAGE_URL} />;
};

// And the component where you want to embed:

<StoreEmbed />;
```

### With an authenticated user

If you are creating a safe session to the store then use this code:

<CodeGroup>
  ```tsx just the component
  import { StorePage } from "@sidedish/react";

  // You get the sessionId from somewhere else
  const StoreEmbed = (sessionId:string) => {
  const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables
  return <StorePage url={STORE_PAGE_URL} sessionId={sessionId} />
  };

  // And the component where you want to embed:
  <StoreEmbed sessionId={sessionId} />;
  ```

  ```tsx Example of frontend to call backend
  import React, {useState, useEffect} from "react";
  import { StorePage } from "@sidedish/react";

  const StoreEmbed = () => {
  const [sessionId, setSessionId] = useState('');
  useEffect(() => {
  	// Prerequisite: You'll need an endpoint that returns the magic link
  	fetch(`/your-backend-service/create-store-session`, { method: "POST" })
  	.then((res) => res.json())
  	.then((result) => setSessionId(result));
  }, []);

  if (!sessionId) return null; // You can also use a loading component of your own

  const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables
  return <StorePage url={STORE_PAGE_URL} sessionId={sessionId} />
  };

  // And the component where you want to embed:
  <StoreEmbed />;
  ```

  ```tsx Example of backend with Next.js

  import { createSafeSession, AcceptableParameters} from "@sidedish/core";
  import { StorePage } from "@sidedish/react";

  //This is a server component
  const StoreEmbed = async ({params} : {params: AcceptableParameters}) => {
  // see docs for "Safe sessions"
  	try {
  		const apiKey = process.env.SIDEDISH_API_KEY!;
  		const domain = process.env.SIDEDISH_DOMAIN!;
  		const {sessionId} = await createSafeSession({apiKey, domain, data: params});

  		const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables
  		return <StorePage url={STORE_PAGE_URL} sessionId={sessionId} />

  	} catch (e) {
  		//do some error handling
  	}
  };

  // And the component where you want to embed:
  <StoreEmbed params={YOUR_PASSED_PARAMS} />;
  ```
</CodeGroup>

### Internal users

To avoid tracking events and analytics made by your internal employees, you can pass true in the `internal` property of the Store component.

Another way to do this is to use the `internal` property of passed `user` object in the unsafeParams or the safe session.

```tsx
    import { StorePage } from "@sidedish/react";
	
	const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables

    const StoreEmbed = () => {
		const isInternalUser = useIsInternalUser(); // your own logic
    	return <StorePage url={STORE_PAGE_URL} internal={isInternalUser} />
    };

    // And the component where you want to embed:
    <StoreEmbed />;

```

## Embedding as an iframe

### Basic usage

If you embed a store without the need for callbacks, then the easiest way to embed that store in your website would be by using an iframe:

<CodeGroup>
  ```html Basic usage
  <iframe
      src="https://YOUR_PAGE_URL"
      style="width: 100%; height: 100%; border: none;"
      allow="clipboard-write"
      loading="lazy"
  >
  </iframe>
  ```
</CodeGroup>

Yes, it's really that simple.

### Specific page

You can embed a specific page in the iframe method by just including `/p/{X}` in the url, where X can be either page id or page slug.

<CodeGroup>
  ```html With a specific page
  <iframe
      src="https://YOUR_PAGE_URL/p/PAGE_ID"
      style="width: 100%; height: 100%; border: none;"
      allow="clipboard-write"
      loading="lazy"
  >
  </iframe>
  ```
</CodeGroup>

### With a safe session

<CodeGroup>
  ```html With a safe session
  <iframe
      src="https://{YOUR_PAGE_URL}?$sessionId={SESSION_ID}"
      style="width: 100%; height: 100%; border: none;"
      allow="clipboard-write"
      loading="lazy"
  >
  </iframe>
  ```
</CodeGroup>

### Internal users

To avoid tracking events and analytics made by your internal employees, you can pass a `$internal=true` parameter in the search params of the url.

Another way to do this is to use the `internal` property of passed `user` object in the unsafeParams or the safe session.

<CodeGroup>
  ```html With for internal employees
  <iframe
      src="https://{YOUR_PAGE_URL}?$internal=true"
      style="width: 100%; height: 100%; border: none;"
      allow="clipboard-write"
      loading="lazy"
  ></iframe>
  ```
</CodeGroup>

## Passing parameters unsafely

We support passing any of the acceptable parameters in an unsafe way if you use them just for display purposes and don't use them for actual effects anyway.

Passing parameters is relatively straight forward, and depends on your implementation:

* In the React component you could include the unsafe params as JSX prop- `unsafeParams`.

* In the iframe method you would simply include the params in the url in a querystring manner but preceding with `$` to guarantee uniqueness-
  `URL?$accountId=SOME_ID&$userId=ANOTHER_ID`. This is only required in the iframe method and not in the react method. Please use JSON.stringify() the values.

<CodeGroup>
  ```tsx React component
  <StorePage url={STORE_PAGE_URL} unsafeParams={{ accountId = 'SOME_ID' }} />
  ```

  ```html Iframe
  <iframe
      src="https://YOUR_PAGE_URL?$accountId=SOME_ID"
      style="width: 100%; height: 100%; border: none;"
      allow="clipboard-write"
      loading="lazy"
  >
  </iframe>
  ```
</CodeGroup>

## Callbacks

We support plenty of actions inside a store, including custom callbacks.

<Steps>
  <Step title="Set origin validation in admin">
    Go to [app.sidedish.com/](https://app.sidedish.com/) and navigate to the desired store settings page. Set up a origin validation hostname and set that up to your domain.
  </Step>

  <Step title="Set a callback for a button somewhere in your store">
    In the layout of the store, define a "Javascript Callback" and set its identifier to a unique string of your liking, that would be the `ACTION_IDENTIFIER`, so you could recognize specific events of that kind. Since a store can have multiple callbacks, the id is used to recognize a specific action. You could however use the same id on multiple places in the store to call for the same callback.
  </Step>

  <Step title="Create your function">
    <Tabs>
      <Tab title="React component">
        If you used the React method that is even simpler as you could just pass a function callback as the property `onCallback`:

        ```tsx
        import { useRef } from 'react';
        import { CallbackEvent } from '@sidedish/react';

        const StoreEmbed = () => {
        	const storeRef = useRef(null);
        	const onCallback = (e: CallbackEvent) => {
        		if (e.actionIdentifier === 'ACTION_IDENTIFIER'){
        			// Do whatever you want.
        			doSomething(e.payload);

        			// 1) If the callback has caused a change in the unsafe params, you can just update the passed `unsafeParams` and the component
        			// will take care of posting an update event for you. This is the same as doing:
        			// storeRef.current.updateUnsafeParams({}) but easier to just update `unsafeParams`

        			// 2) If there was a change in data that is included in the safe session, you can ask the store to reload the session:
        			if (storeRef.current){
        				storeRef.current.reloadSession();
        			}
        		}
        	}

        	const STORE_PAGE_URL = 'YOUR_PAGE_URL'; // Consider saving this in your environment variables
        	return <StorePage url={STORE_PAGE_URL} onCallback={onCallback} ref={storeRef} />;
        };
        ```
      </Tab>

      <Tab title="iframe method">
        If you used the iframe method, just listen to `message` events on your window:

        ```js
        window.addEventListener('message', (event) => {
        	// You should ensure the message is from the expected origin, as plenty of other sources of messages could occur
        	if (event.origin !== "STORE_PAGE_URL") { //Replace with your store url
        		return;
        	}

        	if (event.data.action==='ACTION_IDENTIFIER'){
        		// Do whatever you want.
        		doSomething(even.data);

        		// If the callback has caused an effect that demands a change in the unsafe params, don't update the url of the iframe, as that
        		// will cause the store to rerender. To avoid that, use an accepted message:
        		event.source.postMesage({ type: 'UNSAFE_PARAMS_CHANGE', params: unsafeParams });

        		// If there was a change in data that is included in the safe session, you can ask the store to reload the session:
        		event.source.postMesage({ type: 'SESSION_RELOAD' });
        	}
        });
        ```
      </Tab>
    </Tabs>

    The props of the event are:

    <ResponseField name="actionIdentifier" type="string">
      The action id that you've set in the admin dashboard
    </ResponseField>

    <ResponseField name="payload" type="object">
      <Expandable title="payload">
        <ResponseField name="productId">
          The `id` of the product.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Step>

  <Step title="Test">
    Make sure everything works as intended.
  </Step>
</Steps>

## Path changes

Preserving path changes provides the user with a bookmarkable page in the store, and is highly recommended.

<Tabs>
  <Tab title="React component">
    <Steps>
      <Step title="Pass current page to store">
        Store `url` should reflect the page from the browser. The implementation depends on your code.
      </Step>

      <Step title="Register changes in store and reflect in browser history">
        Listen to `onPathChange` callback on the Store.
      </Step>
    </Steps>

    ```tsx
    import { StorePage } from '@sidedish/react';

    const StoreEmbed = () => {
    const STORE_PAGE_URL = 'YOUR_PAGE_URL';
    const STORE_PAGE_PATH = '/my-marketplace';

        const onPathChange = (path:string) => {
        	window.history.pushState({}, '', `${STORE_PAGE_PATH}${path}`);
        }

        const pathname = window.location.pathname.replace(STORE_PAGE_PATH, '');
        const url = `${STORE_PAGE_URL}${pathname}`;
        return <StorePage url={url} onPathChange={onPathChange} />;

    };

    ```
  </Tab>

  <Tab title="iframe method">
    If you used the iframe method, just listen to `message` events on your window:

    ```js
    window.addEventListener('message', (event) => {
    	// You should ensure the message is from the expected origin, as plenty of other sources of messages could occur
    	if (event.origin !== "STORE_PAGE_URL") return; //Replace with your store url

    	if (event.data.type==='STORE_PATH_CHANGE'){
    		const path = event.data.path;
    		const STORE_PAGE_PATH = '/my-marketplace';
    		window.history.pushState({}, '', `${STORE_PAGE_PATH}${path}`);
    	}
    });
    ```
  </Tab>
</Tabs>
