Skip to content
Merged
74 changes: 74 additions & 0 deletions docs/COMPONENT_CUSTOMIZATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ Available component types include:
- `statement` - Statement/information display
- `table` - Table components
- `drawer` - Drawer components
- `forcedValue` - Forced value components
- `zendeskDrawer` - Zendesk drawer components
- `zendeskTriggerButton` - Zendesk trigger button components
- `pdfViewer` - PDF viewer component
- `tel` - Tel field component
- `time` - Time field component
Expand All @@ -117,6 +119,7 @@ and their typescript definitions
- `ButtonComponentProps`: For custom button components
- `StatementComponentProps`: For custom statement components
- `ZendeskDrawerComponentProps`: For custom zendesk drawer
- `ZendeskTriggerButtonComponentProps`: For custom zendesk trigger button
- `FileComponentProps`: for custom file field components
- `CountryComponentProps`: for country field components
- `TextFieldComponentProps`: for textfield components
Expand All @@ -125,6 +128,7 @@ and their typescript definitions
- `PDFPreviewComponentProps`: for the pdf viewer component
- `TelFieldComponentProps`: for the tel component
- `TimeFieldComponentProps`: for the timefield component
- `ForcedValueComponentProps`: for the forced value component

> **Tip:** Check [src/default-components.ts](../src/default-components.ts) to see the default implementations. You can use these as a starting point or reference when building your own custom components.

Expand Down Expand Up @@ -393,6 +397,76 @@ type JSFCustomComponentProps = {
};
```

### ZendeskTriggerButtonComponentProps

For custom Zendesk trigger button components:

```tsx
import { ZendeskTriggerButtonComponentProps } from '@remoteoss/remote-flows';

type ZendeskTriggerButtonComponentProps = {
zendeskId: number;
className?: string;
onClick?: (zendeskId: number) => void;
children?: React.ReactNode;
external?: boolean;
} & Record<string, unknown>;
```

**Example: Custom Zendesk Trigger Button**

```tsx
import {
RemoteFlows,
ZendeskTriggerButtonComponentProps,
} from '@remoteoss/remote-flows';

const CustomZendeskTriggerButton = ({
zendeskId,
onClick,
children,
className,
external,
}: ZendeskTriggerButtonComponentProps) => {
const handleClick = () => {
onClick?.(zendeskId);
};

if (external) {
return (
<a
href={`https://support.example.com/article/${zendeskId}`}
target='_blank'
rel='noopener noreferrer'
onClick={handleClick}
className={className}
>
{children}
</a>
);
}

return (
<button onClick={handleClick} className={className}>
{children}
</button>
);
};

function App() {
return (
<RemoteFlows
auth={fetchToken}
components={{
zendeskTriggerButton: CustomZendeskTriggerButton,
}}
>
{/* All flows will use this custom Zendesk trigger button */}
</RemoteFlows>
);
}
```

## When to Use Each Method

### Use Global Override When:
Expand Down
59 changes: 48 additions & 11 deletions example/src/Components.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import type {
ButtonComponentProps,
Components,
FieldComponentProps,
FieldSetToggleComponentProps,
FileComponentProps,
ForcedValueComponentProps,
PDFPreviewComponentProps,
TelFieldComponentProps,
TimeFieldComponentProps,
import {
buildZendeskURL,
type ButtonComponentProps,
type Components,
type FieldComponentProps,
type FieldSetToggleComponentProps,
type FileComponentProps,
type ForcedValueComponentProps,
type PDFPreviewComponentProps,
type TelFieldComponentProps,
type TimeFieldComponentProps,
type ZendeskTriggerButtonComponentProps,
} from '@remoteoss/remote-flows';
import { FileUploader } from '@remoteoss/remote-flows/internals';
import { cn, FileUploader } from '@remoteoss/remote-flows/internals';
import { splitAccordionDescription } from './utils/transformHtml';
import { Accordion } from './components/Accordion';
//import { ZendeskDialog } from './ZendeskDialog';
Expand Down Expand Up @@ -491,6 +493,40 @@ const TimeField = ({
);
};

const ZendeskTriggerButton = ({
zendeskId,
onClick,
children,
external,
className,
}: ZendeskTriggerButtonComponentProps) => {
const handleClick = () => {
onClick?.(zendeskId);
};

if (external) {
return (
<a
href={buildZendeskURL(zendeskId)}
target='_blank'
rel='noopener noreferrer'
className={cn('zendesk-custom-button zendesk-link', className)}
>
{children}
</a>
);
}

return (
<button
onClick={handleClick}
className={cn('zendesk-custom-button', className)}
>
{children}
</button>
);
};

export const components: Components = {
button: Button,
text: Input,
Expand All @@ -506,5 +542,6 @@ export const components: Components = {
pdfViewer: PDFPreview,
tel: TelField,
time: TimeField,
zendeskTriggerButton: ZendeskTriggerButton,
//zendeskDrawer: ZendeskDialog,
};
42 changes: 21 additions & 21 deletions src/components/shared/zendesk-drawer/ZendeskTriggerButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { cn } from '@/src/lib/utils';
import { ZendeskDrawer } from './ZendeskDrawer';
import { buildZendeskURL } from './utils';
import { useState } from 'react';
import { useFormFields } from '@/src/context';

interface ZendeskTriggerButtonProps {
/**
Expand All @@ -26,16 +25,14 @@ interface ZendeskTriggerButtonProps {
external?: boolean;
}

const baseClassName =
'RemoteFlows__ZendeskTriggerButton text-blue-500 hover:underline inline-block text-xs bg-transparent border-none cursor-pointer p-0';

export function ZendeskTriggerButton({
zendeskId,
className,
onClick,
children,
external = false,
}: ZendeskTriggerButtonProps) {
const { components } = useFormFields();
const [isOpen, setIsOpen] = useState(false);

const handleClick = () => {
Expand All @@ -45,30 +42,33 @@ export function ZendeskTriggerButton({
onClick?.(zendeskId);
};

const CustomZendeskTriggerButton = components?.zendeskTriggerButton;

if (!CustomZendeskTriggerButton) {
throw new Error(`Zendesk trigger button component not found`);
}

const triggerElement = (
<CustomZendeskTriggerButton
zendeskId={zendeskId}
className={className}
onClick={handleClick}
external={external}
>
{children}
</CustomZendeskTriggerButton>
);

if (external) {
return (
<a
href={buildZendeskURL(zendeskId)}
target='_blank'
rel='noopener noreferrer'
onClick={handleClick}
className={cn(baseClassName, className)}
>
{children}
</a>
);
return triggerElement;
}

return (
<ZendeskDrawer
zendeskId={zendeskId}
open={isOpen}
onClose={() => setIsOpen(false)}
Trigger={
<button onClick={handleClick} className={cn(baseClassName, className)}>
{children}
</button>
}
Trigger={triggerElement}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ZendeskTriggerButtonComponentProps } from '@/src/types/remoteFlows';
import { cn } from '@/src/lib/utils';
import { buildZendeskURL } from '../utils';

const baseClassName =
'RemoteFlows__ZendeskTriggerButton text-blue-500 hover:underline inline-block text-xs bg-transparent border-none cursor-pointer p-0';

export function ZendeskTriggerButtonDefault({
zendeskId,
onClick,
children,
className,
external,
}: ZendeskTriggerButtonComponentProps) {
const handleClick = () => {
onClick?.(zendeskId);
};

if (external) {
return (
<a
href={buildZendeskURL(zendeskId)}
target='_blank'
rel='noopener noreferrer'
onClick={handleClick}
className={cn(baseClassName, className)}
>
{children}
</a>
);
}

return (
<button onClick={handleClick} className={cn(baseClassName, className)}>
{children}
</button>
);
}
Loading
Loading