@freshworks/react-native-freshdesk-sdk
Version:
React Native wrapper for Freshdesk Android and iOS SDKs
350 lines (321 loc) • 9.89 kB
text/typescript
import type { EmitterSubscription } from 'react-native';
import { nativeModule, eventEmitter, isNativeModuleAvailable } from './FreshdeskModule';
import { FreshdeskEvents } from './events';
import { parseDiagnosticReport } from './diagnostics';
import { normalizeFreshdeskHost } from './utils/normalizeHost';
import type {
FreshdeskConfig,
TopicInfo,
UserProperties,
TicketProperties,
EventProperties,
UnreadCountEvent,
UserStateEvent,
LinkPressedEvent,
UserCreatedEvent,
ResetUserResult,
ContentConfiguration,
UserData,
DiagnosticReport,
} from './types';
export { FreshdeskEvents } from './events';
export type { FreshdeskEventName } from './events';
export type {
FreshdeskConfig,
TopicInfo,
UserProperties,
TicketProperties,
EventProperties,
UnreadCountEvent,
UserStateEvent,
LinkPressedEvent,
UserCreatedEvent,
ResetUserResult,
ContentConfiguration,
HeaderContent,
PlaceholderContent,
PrivacyPolicyContent,
ActionContent,
ChannelResponseContent,
ChannelResponseOnline,
ChannelResponseTimeUnit,
TicketFormContent,
UserData,
SDKVersion,
DiagnosticStatus,
DiagnosticCheck,
DiagnosticReport,
} from './types';
export { UserState, FreshdeskErrorCode } from './types';
export { formatDiagnosticReport, parseDiagnosticReport } from './diagnostics';
export { normalizeFreshdeskHost, isBareFreshdeskHost } from './utils/normalizeHost';
/**
* Initialize the Freshdesk SDK with configuration
* Must be called before any other SDK methods
* @param config SDK configuration
*/
export function initialize(config: FreshdeskConfig): Promise<void> {
if (!isNativeModuleAvailable) {
return Promise.reject(new Error('Freshdesk native module not available'));
}
return nativeModule.initialize({
...config,
host: normalizeFreshdeskHost(config.host),
});
}
/**
* Open the Freshdesk support home screen
*/
export function openSupport(): Promise<void> {
return nativeModule.openSupport();
}
/**
* Open the Freshdesk knowledge base / FAQ screen
*/
export function openKnowledgeBase(): Promise<void> {
return nativeModule.openKnowledgeBase();
}
/**
* Open a specific support topic
* @param topic Topic information (name and optional ID)
*/
export function openTopic(topic: TopicInfo): Promise<void> {
return nativeModule.openTopic(topic.topicName, topic.topicId ?? '');
}
/**
* Get the current unread message count
*
* Platform note: on Android this resolves a cached, broadcast-driven value and
* is `0` until the first broadcast arrives after `initialize()`; on iOS it is
* live. Prefer {@link addUnreadCountListener} for a value you can trust
* immediately on both platforms. See PLATFORM_DIFFERENCES.md.
*
* @returns Promise resolving to the unread count
*/
export function getUnreadCount(): Promise<number> {
return nativeModule.getUnreadCount();
}
/**
* Track a user event for analytics and context
* @param name Event name
* @param properties Event properties
*/
export function trackEvent(name: string, properties?: EventProperties): Promise<void> {
return nativeModule.trackEvent(name, properties ?? {});
}
/**
* Set user properties (only for non-JWT enforced SDKs)
* @param properties User properties
*/
export function setUserProperties(properties: UserProperties): Promise<void> {
return nativeModule.setUserProperties(properties);
}
/**
* Set ticket properties
* @param properties Ticket properties
*/
export function setTicketProperties(properties: TicketProperties): Promise<void> {
return nativeModule.setTicketProperties(properties);
}
/**
* Authenticate or update user with JWT token
* @param jwt JWT token
*/
export function authenticateAndUpdate(jwt: string): Promise<void> {
return nativeModule.authenticateAndUpdate(jwt);
}
/**
* Reset the current user and clear session data
* Call this when user logs out
*
* Platform note: Android can resolve `{ success: false, error }` on a genuine
* reset failure; iOS's native SDK has no failure callback for this operation
* and always resolves `{ success: true }` once initialized (it only rejects
* for the not-initialized usage error). Don't rely on `success: false` as a
* cross-platform signal. See PLATFORM_DIFFERENCES.md.
*/
export function resetUser(): Promise<ResetUserResult> {
return nativeModule.resetUser().then((r) => {
const result: ResetUserResult = { success: r.success };
if (r.message) {
result.message = r.message;
}
if (r.error) {
result.error = r.error;
}
return result;
});
}
/**
* Dismiss any open Freshdesk views
*/
export function dismiss(): Promise<void> {
return nativeModule.dismiss();
}
/**
* Set a custom link handler
* When a link is pressed in the SDK, an event will be emitted
* @param handler Callback function to handle link presses
* @returns EmitterSubscription to remove the listener
*/
export function setLinkHandler(
handler: (event: LinkPressedEvent) => void
): EmitterSubscription | null {
if (!eventEmitter) {
console.warn('Freshdesk event emitter not available');
return null;
}
// Enable link handler in native module
nativeModule.setLinkHandlerEnabled(true).catch((err: Error) => {
console.warn('Failed to enable link handler:', err);
});
return eventEmitter.addListener(FreshdeskEvents.ON_LINK_PRESSED, handler);
}
/**
* Add a listener for unread count changes
* @param listener Callback function receiving the unread count
* @returns EmitterSubscription to remove the listener
*/
export function addUnreadCountListener(
listener: (event: UnreadCountEvent) => void
): EmitterSubscription | null {
if (!eventEmitter) {
console.warn('Freshdesk event emitter not available');
return null;
}
return eventEmitter.addListener(FreshdeskEvents.UNREAD_COUNT_CHANGED, listener);
}
/**
* Add a listener for user state changes
* @param listener Callback function receiving the user state
* @returns EmitterSubscription to remove the listener
*/
export function addUserStateListener(
listener: (event: UserStateEvent) => void
): EmitterSubscription | null {
if (!eventEmitter) {
console.warn('Freshdesk event emitter not available');
return null;
}
return eventEmitter.addListener(FreshdeskEvents.USER_STATE_CHANGED, listener);
}
/**
* Add a listener for user creation events
* @param listener Callback function receiving user creation event
* @returns EmitterSubscription to remove the listener
*/
export function addUserCreatedListener(
listener: (event: UserCreatedEvent) => void
): EmitterSubscription | null {
if (!eventEmitter) {
console.warn('Freshdesk event emitter not available');
return null;
}
return eventEmitter.addListener(FreshdeskEvents.USER_CREATED, listener);
}
/**
* Remove all Freshdesk event listeners
* Call this when cleaning up (e.g., on component unmount)
*/
export function removeAllListeners(): void {
if (!eventEmitter) {
return;
}
eventEmitter.removeAllListeners(FreshdeskEvents.UNREAD_COUNT_CHANGED);
eventEmitter.removeAllListeners(FreshdeskEvents.USER_STATE_CHANGED);
eventEmitter.removeAllListeners(FreshdeskEvents.USER_CREATED);
eventEmitter.removeAllListeners(FreshdeskEvents.ON_LINK_PRESSED);
// Disable link handler
nativeModule.setLinkHandlerEnabled(false).catch(() => {
// Ignore errors when disabling
});
}
/**
* Get the SDK version string
* @returns Promise resolving to SDK version (e.g., "1.0.1")
*/
export function getSDKVersion(): Promise<string> {
if (!isNativeModuleAvailable) {
return Promise.resolve('unknown');
}
return nativeModule.getSDKVersion();
}
/**
* Get the current user information from the SDK
* @returns Promise resolving to user data object
*/
export async function getUser(): Promise<UserData> {
if (!isNativeModuleAvailable) {
return Promise.resolve({});
}
const userJson = await nativeModule.getUser();
try {
return JSON.parse(userJson) as UserData;
} catch {
return {};
}
}
/**
* Set content configuration to customize SDK UI text
* @param config Content configuration for headers, placeholders, etc.
*/
export function setContentConfiguration(config: ContentConfiguration): Promise<void> {
if (!isNativeModuleAvailable) {
return Promise.reject(new Error('Freshdesk native module not available'));
}
const configString = JSON.stringify(config);
return nativeModule.setContentConfiguration(configString);
}
/**
* Enable or disable Freshdesk SDK debug logs
*
* Platform note: reliable at runtime on iOS only. On Android, debug logging
* can only be set at `initialize()` time (`debugMode: true`); calling this
* afterward is a no-op there. See PLATFORM_DIFFERENCES.md.
*
* @param enabled Whether debug logging should be enabled
*/
export function enableDebugLogs(enabled: boolean): Promise<void> {
if (!isNativeModuleAvailable) {
return Promise.reject(new Error('Freshdesk native module not available'));
}
return nativeModule.enableDebugLogs(enabled);
}
/**
* Run Freshdesk SDK diagnostics and return a structured report
*/
export async function runDiagnostics(): Promise<DiagnosticReport> {
if (!isNativeModuleAvailable) {
return parseDiagnosticReport(await nativeModule.runDiagnostics());
}
const raw = await nativeModule.runDiagnostics();
return parseDiagnosticReport(raw);
}
/**
* Freshdesk SDK object for convenient access
*/
export const FreshdeskSDK = {
initialize,
openSupport,
openKnowledgeBase,
openTopic,
getUnreadCount,
trackEvent,
setUserProperties,
setTicketProperties,
authenticateAndUpdate,
resetUser,
dismiss,
setLinkHandler,
addUnreadCountListener,
addUserStateListener,
addUserCreatedListener,
removeAllListeners,
getSDKVersion,
getUser,
setContentConfiguration,
enableDebugLogs,
runDiagnostics,
events: FreshdeskEvents,
};
export default FreshdeskSDK;