Skip to content

Commit

Permalink
Zendesk: Vanilla and React integration (#111)
Browse files Browse the repository at this point in the history
* feat: Update dependencies to latest versions

Co-authored-by: Matias Pompilio <matias.pompilio@nan-labs.com>
Co-authored-by: Ulises Jeremias <ulisescf.24@gmail.com>

* feat: Update dependencies to latest versions

* feat: Add zendesk export to react-thirdparty package

* feat: Add Zendesk integration to react-thirdparty package

* feat: Add Zendesk integration to react-thirdparty package

* feat: Refactor Zendesk integration in react-thirdparty package

This commit refactors the Zendesk integration in the react-thirdparty package. It updates the `ZendeskContextProps` interface in `Context.tsx` to use the `ZendeskWidget` type instead of `any`. It also updates the `ZendeskProvider` component in `Provider.tsx` to use the `ZendeskWidget` type for the `zendeskClient` state and the `executeZendesk` function.

Co-authored-by: Matias Pompilio <matias.pompilio@nan-labs.com>
Co-authored-by: Ulises Jeremias <ulisescf.24@gmail.com>

* refactor: Update Zendesk integration in react-thirdparty package

* refactor: Update Zendesk integration in react-thirdparty package

* chore: Update third-party scripts to include source URLs

Co-authored-by: Matias Pompilio <matias.pompilio@nan-labs.com>
Co-authored-by: Ulises Jeremias <ulisescf.24@gmail.com>

---------

Co-authored-by: Matias Pompilio <matias.pompilio@nan-labs.com>
  • Loading branch information
ulises-jeremias and matiaspompilio authored Jul 4, 2024
1 parent 6811d6b commit ffe7c5c
Show file tree
Hide file tree
Showing 21 changed files with 586 additions and 23 deletions.
8 changes: 8 additions & 0 deletions .changeset/curvy-bikes-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@nanlabs/react-thirdparty": minor
"@nanlabs/thirdparty": minor
"@nanlabs/playground": patch
"tsconfig": patch
---

Added Zendesk integration
120 changes: 120 additions & 0 deletions apps/playground/src/stories/react-thirdparty/Zendesk.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Meta } from "@storybook/addon-docs";

<Meta title="React Thirdparty/Zendesk" />

<h1 align="center">React Zendesk Integration</h1>
<div align="center">

Integrating Zendesk

</div>

## Usage

### Provide Zendesk Key

To use this integration, you need to create a Zendesk key for your domain.

### Components

#### ZendeskProvider

`ZendeskProvider` is a React component that wraps your application and loads the Zendesk script. It provides context to other components and hooks that need to interact with Zendesk.

```jsx
import { ZendeskProvider } from "@nanlabs/react-thirdparty";

const App = () => (
<ZendeskProvider
zendeskKey="[Your zendesk key]"
scriptId="zendesk-script"
handleOnLoad={() => console.log("Zendesk script loaded!")}
>
<YourApp />
</ZendeskProvider>
);

export default App;
```

#### Zendesk Component

`Zendesk` is a React component that can be used in your app to load the Zendesk script. It utilizes the context provided by `ZendeskProvider`.

```jsx
import React from "react";
import { Zendesk } from "@nanlabs/react-thirdparty";

const YourComponent = () => (
<div>
<Zendesk />
</div>
);

export default YourComponent;
```

### React Hook: useZendesk

If you prefer a React Hook approach, you can choose to use the custom hook `useZendesk`.

It's very simple to use the hook:

```tsx
import React from "react";
import { useZendesk } from "@nanlabs/react-thirdparty";

const YourZendeskComponent = () => {
const { executeZendesk } = useZendesk();

return (
<div>
<button onClick={() => executeZendesk('webWidget', 'open')}>
Open Zendesk Widget
</button>
</div>
);
};

export default YourZendeskComponent;
```

## More Examples!

### Zendesk Component Example

```jsx
import React from "react";
import { ZendeskProvider, Zendesk } from "@nanlabs/react-thirdparty";

export const ZendeskComponentExample = () => (
<ZendeskProvider zendeskKey="YOUR_ZENDESK_KEY" scriptId="zendesk-script">
<Zendesk />
</ZendeskProvider>
);
```

### useZendesk Hook Example

```jsx
import React from "react";
import { ZendeskProvider, useZendesk } from "@nanlabs/react-thirdparty";

export const UseZendeskHookExample = () => {
const { executeZendesk } = useZendesk();

return (
<div>
<button onClick={() => executeZendesk('webWidget', 'open')}>
Open Zendesk Widget
</button>
</div>
);
};

export const UseZendeskHookExampleWrapped = () => (
<ZendeskProvider zendeskKey="YOUR_ZENDESK_KEY" scriptId="zendesk-script">
<UseZendeskHookExample />
</ZendeskProvider>
);
```
1 change: 1 addition & 0 deletions packages/react-thirdparty/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./recaptcha";
export * from "./zendesk";
5 changes: 4 additions & 1 deletion packages/react-thirdparty/recaptcha/Context.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createContext } from "react";
import { createContext, useContext } from "react";
import { ReCaptchaExecuteOptions } from "./Provider";

export interface GoogleReCaptchaConsumerProps {
Expand All @@ -12,3 +12,6 @@ const GoogleReCaptchaContext = createContext<GoogleReCaptchaConsumerProps>({
const { Consumer: GoogleReCaptchaConsumer } = GoogleReCaptchaContext;

export { GoogleReCaptchaConsumer, GoogleReCaptchaContext };

export const useGoogleReCaptchaContext = () =>
useContext(GoogleReCaptchaContext);
4 changes: 2 additions & 2 deletions packages/react-thirdparty/recaptcha/GoogleReCaptcha.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FC } from "react";
import React, { FC } from "react";
import {
GoogleReCaptchaConfig,
useGoogleReCaptcha,
} from "./useGoogleReCaptcha";

export const GoogleReCaptcha: FC<GoogleReCaptchaConfig> = (config) => {
useGoogleReCaptcha(config);
return null;
return <div id="google-recaptcha-container" />;
};
10 changes: 7 additions & 3 deletions packages/react-thirdparty/recaptcha/Provider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React, { FC, useCallback, useEffect, useState } from "react";
import { GoogleReCaptchaContext } from "./Context";
import { injectGoogleReCaptchaScript, removeScript } from "@nanlabs/thirdparty";
import {
GoogleReCaptchaSrc,
injectGoogleReCaptchaScript,
removeGoogleReCaptchaScript,
} from "@nanlabs/thirdparty";

const SCRIPT_ID = "google-recaptcha-v3";

Expand Down Expand Up @@ -38,7 +42,7 @@ export const GoogleReCaptchaProvider: FC<GoogleReCaptchaProviderProps> = ({
}) => {
const [grecaptcha, setGrecaptcha] = useState<ReCaptchaInstance | null>(null);

const googleRecaptchaSrc = () => {
const googleRecaptchaSrc = (): GoogleReCaptchaSrc => {
const hostName = useRecaptchaNet ? "recaptcha.net" : "google.com";

return `https://www.${hostName}/recaptcha/api.js`;
Expand Down Expand Up @@ -83,7 +87,7 @@ export const GoogleReCaptchaProvider: FC<GoogleReCaptchaProviderProps> = ({

return () => {
// remove badge and script
removeScript(SCRIPT_ID);
removeGoogleReCaptchaScript(SCRIPT_ID);
};
}, [reCaptchaKey]);

Expand Down
1 change: 0 additions & 1 deletion packages/react-thirdparty/recaptcha/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from "./useGoogleReCaptcha";
export * from "./useGoogleReCaptchaContext";
export * from "./GoogleReCaptcha";
export * from "./Context";
export * from "./Provider";
2 changes: 1 addition & 1 deletion packages/react-thirdparty/recaptcha/useGoogleReCaptcha.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect } from "react";
import { useGoogleReCaptchaContext } from "./useGoogleReCaptchaContext";
import { useGoogleReCaptchaContext } from "./Context";

export interface GoogleReCaptchaConfig {
onVerify: (token: string) => void | Promise<void>;
Expand Down

This file was deleted.

14 changes: 14 additions & 0 deletions packages/react-thirdparty/zendesk/Context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext, useContext } from "react";

export interface ZendeskContextProps {
executeZendesk?: ZendeskMessagingWidget;
}

export const ZendeskContext = createContext<ZendeskContextProps>({});

/**
* Custom hook to use the Zendesk context.
* @throws If used outside of a ZendeskProvider.
* @returns The Zendesk context value.
*/
export const useZendeskContext = () => useContext(ZendeskContext);
53 changes: 53 additions & 0 deletions packages/react-thirdparty/zendesk/Provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useEffect, ReactNode, useState } from "react";
import { ZendeskContext } from "./Context";
import {
injectZendeskScript,
removeZendeskScript,
ZendeskScriptProps,
} from "@nanlabs/thirdparty";

/**
* ZendeskProvider component to wrap around your application and provide Zendesk context.
* @param props - The props for the provider.
* @returns The provider component.
*/
export const ZendeskProvider: React.FC<
ZendeskScriptProps & { children: ReactNode }
> = ({ zendeskKey, scriptId, appendTo = "body", handleOnLoad, children }) => {
const [zendeskClient, setZendeskClient] = useState<
ZendeskMessagingWidget | undefined
>(undefined);

const onLoad = () => {
if (!window?.zE) {
console.warn("Zendesk script is not available");
return;
}
setZendeskClient(window.zE);
if (handleOnLoad) {
handleOnLoad();
}
};

useEffect(() => {
injectZendeskScript({
zendeskKey,
scriptId,
appendTo,
handleOnLoad: onLoad,
});

return () => {
removeZendeskScript(scriptId);
setZendeskClient(undefined);
};
}, [zendeskKey, scriptId, appendTo, handleOnLoad]);

const zendeskContextValue = { executeZendesk: zendeskClient };

return (
<ZendeskContext.Provider value={zendeskContextValue}>
{children}
</ZendeskContext.Provider>
);
};
82 changes: 82 additions & 0 deletions packages/react-thirdparty/zendesk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<h1 align="center">React Zendesk Integration</h1>
<div align="center">

Integrating Zendesk into your React application

</div>

## Usage

### Provide API Key

To use these integrations, you need to create an API key for your domain. You can get one from [here](https://www.zendesk.com/).

### Components

### Zendesk

To use the Zendesk integration, you need to include the `ZendeskProvider` in your application and use the `Zendesk` component or the `useZendesk` hook.

#### ZendeskProvider

`ZendeskProvider` is a React component that wraps your application and loads the Zendesk script. It provides context to other components and hooks that need to interact with Zendesk.

```jsx
import { ZendeskProvider } from "@nanlabs/react-thirdparty";

const App = () => (
<ZendeskProvider
zendeskKey="[Your zendesk key]"
scriptId="zendesk-script"
handleOnLoad={() => console.log("Zendesk script loaded!")}
>
<YourApp />
</ZendeskProvider>
);

export default App;
```

#### Zendesk Component

`Zendesk` is a React component that can be used in your app to load the Zendesk script. It utilizes the context provided by `ZendeskProvider`.

```jsx
import React, { useEffect } from "react";
import { Zendesk } from "@nanlabs/react-thirdparty";

const YourComponent = () => (
<div>
<Zendesk />
</div>
);

export default YourComponent;
```

### React Hook: useZendesk

If you prefer a React Hook approach, you can choose to use the custom hook `useZendesk`.

It's very simple to use the hook:

```tsx
import React from "react";
import { useZendesk } from "@nanlabs/react-thirdparty";

const YourZendeskComponent = () => {
const { executeZendesk } = useZendesk();

return (
<div>
<button onClick={() => executeZendesk("webWidget", "open")}>
Open Zendesk Widget
</button>
</div>
);
};

export default YourZendeskComponent;
```

By following these steps, you can integrate Zendesk into your project using either a React hook or a component, providing flexibility depending on your needs.
29 changes: 29 additions & 0 deletions packages/react-thirdparty/zendesk/Zendesk.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { FC, useEffect } from "react";
import { useZendesk } from "./useZendesk";

/**
* Zendesk component to load the Zendesk script.
* @returns The Zendesk container element.
*/
const Zendesk: React.FC = () => {
const { executeZendesk } = useZendesk();

useEffect(() => {
if (!executeZendesk) {
console.warn("Zendesk client is not available");
return;
}

// Example usage of executeZendesk when the component mounts
executeZendesk("messenger", "open");

return () => {
// Example cleanup if needed
executeZendesk("messenger", "close");
};
}, [executeZendesk]);

return <div id="zendesk-container"></div>;
};

export default Zendesk;
4 changes: 4 additions & 0 deletions packages/react-thirdparty/zendesk/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { useZendeskContext } from "./Context";
export { ZendeskProvider } from "./Provider";
export { useZendesk } from "./useZendesk";
export { default as Zendesk } from "./Zendesk";
Loading

0 comments on commit ffe7c5c

Please sign in to comment.