Skip to content

Commit

Permalink
Embedded received event (#278)
Browse files Browse the repository at this point in the history
* change in embedded api params

* Update EmbeddedMsgs.tsx (#263)

* Update index.tsx (#264)

* Update index.tsx (#265)

* Update index.tsx (#266)

* Update embeddedManager.ts (#267)

* Update index.ts (#268)

* Update events.schema.ts (#270)

* Update types.ts (#271)

* Update yarn.lock (#272)

* Create IterableActionRunner.ts (#274)

* Update embeddedManager.ts (#276)

* Update types.ts (#277)

* Resolve build fail issue (#289)

* Resolve merge conflicts
  • Loading branch information
hani-iterable authored Jan 4, 2024
1 parent 47ab4f4 commit 198ecf6
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 17 deletions.
57 changes: 50 additions & 7 deletions react-example/src/views/EmbeddedMsgs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import {
} from '@iterable/web-sdk';
import Button from 'src/components/Button';
import TextField from 'src/components/TextField';
import { IterableActionSource, IterableActionRunner } from '@iterable/web-sdk';

interface Props {}

export const EmbeddedMsgs: FC<Props> = () => {
const [selectedButtonIndex, setSelectedButtonIndex] = useState(0);
const [userId, setUserId] = useState<string>();
const [messages, setMessages] = useState([]);
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const iterableActionRunner = new IterableActionRunner();

useEffect(() => {
initialize(process.env.API_KEY);
Expand All @@ -25,8 +26,7 @@ export const EmbeddedMsgs: FC<Props> = () => {
try {
const embeddedManager = new EmbeddedManager();
await embeddedManager.syncMessages(
emailRegex.test(userId) ? '' : userId,
emailRegex.test(userId) ? userId : '',
userId,
'Web',
'1',
'my-website',
Expand All @@ -39,10 +39,17 @@ export const EmbeddedMsgs: FC<Props> = () => {
}
};

const handleOpenUrl = (type: string, url: string) => {
if (type === 'openUrl') {
global.open(url, '_blank', 'noopener,noreferrer');
}
const handleOpenUrl = (clickedUrl: string, data: string) => {
const iterableAction = {
type: clickedUrl,
data
};

iterableActionRunner.executeAction(
null,
iterableAction,
IterableActionSource.EMBEDDED
);
};

return (
Expand Down Expand Up @@ -159,6 +166,18 @@ export const EmbeddedMsgs: FC<Props> = () => {
message?.elements?.buttons[0]?.action?.data
);
}}
onClickSecondaryBtn={() => {
handleOpenUrl(
message?.elements?.buttons[1]?.action?.type,
message?.elements?.buttons[1]?.action?.data
);
}}
onClickView={() => {
handleOpenUrl(
message?.elements?.defaultAction?.type,
message?.elements?.defaultAction?.data
);
}}
/>
))}

Expand Down Expand Up @@ -195,6 +214,18 @@ export const EmbeddedMsgs: FC<Props> = () => {
message?.elements?.buttons[0]?.action?.data
);
}}
onClickSecondaryBtn={() => {
handleOpenUrl(
message?.elements?.buttons[1]?.action?.type,
message?.elements?.buttons[1]?.action?.data
);
}}
onClickView={() => {
handleOpenUrl(
message?.elements?.defaultAction?.type,
message?.elements?.defaultAction?.data
);
}}
/>
))}

Expand Down Expand Up @@ -223,6 +254,18 @@ export const EmbeddedMsgs: FC<Props> = () => {
message?.elements?.buttons[0]?.action?.data
);
}}
onClickSecondaryBtn={() => {
handleOpenUrl(
message?.elements?.buttons[1]?.action?.type,
message?.elements?.buttons[1]?.action?.data
);
}}
onClickView={() => {
handleOpenUrl(
message?.elements?.defaultAction?.type,
message?.elements?.defaultAction?.data
);
}}
/>
))}
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/banner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface IBannerProps {
textStyle?: CSSProperties;
primaryBtnStyle?: CSSProperties;
secondaryBtnStyle?: CSSProperties;
onClickView?: () => void;
}

export const Banner = (props: IBannerProps) => {
Expand All @@ -34,7 +35,8 @@ export const Banner = (props: IBannerProps) => {
secondaryBtnLabel,
secondaryBtnStyle,
textStyle,
titleStyle
titleStyle,
onClickView
} = props;

const defaultBannerStyles = {
Expand Down Expand Up @@ -85,6 +87,7 @@ export const Banner = (props: IBannerProps) => {
...defaultBannerStyles,
...BannerStyle
}}
onClick={onClickView}
>
<div
style={{
Expand Down
6 changes: 4 additions & 2 deletions src/components/card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface ICardProps {
textStyle?: CSSProperties;
primaryBtnStyle?: CSSProperties;
secondaryBtnStyle?: CSSProperties;
onClickView?: () => void;
}

export const Card = (props: ICardProps) => {
Expand All @@ -34,7 +35,8 @@ export const Card = (props: ICardProps) => {
secondaryBtnLabel,
secondaryBtnStyle,
textStyle,
titleStyle
titleStyle,
onClickView
} = props;

const defaultCardStyles = {
Expand Down Expand Up @@ -80,7 +82,7 @@ export const Card = (props: ICardProps) => {
};

return (
<div style={{ ...defaultCardStyles, ...cardStyle }}>
<div style={{ ...defaultCardStyles, ...cardStyle }} onClick={onClickView}>
<img
style={{ ...defaultImageStyles, ...imgStyle }}
src={imgSrc ? imgSrc : '../../assets/iterable_logo.png'}
Expand Down
6 changes: 4 additions & 2 deletions src/components/notification/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface NotificationProps {
secondaryButtonStyle?: CSSProperties;
onClickPrimaryBtn?: () => void;
onClickSecondaryBtn?: () => void;
onClickView?: () => void;
}

export const Notification: React.FC<NotificationProps> = ({
Expand All @@ -19,7 +20,8 @@ export const Notification: React.FC<NotificationProps> = ({
primaryButtonStyle,
secondaryButtonStyle,
onClickPrimaryBtn,
onClickSecondaryBtn
onClickSecondaryBtn,
onClickView
}) => {
const cardStyle: CSSProperties = {
background: 'white',
Expand Down Expand Up @@ -48,7 +50,7 @@ export const Notification: React.FC<NotificationProps> = ({
};

return (
<div style={cardStyle}>
<div style={cardStyle} onClick={onClickView}>
<h2>{title}</h2>
<p>{description}</p>
{primaryButtonLabel && (
Expand Down
120 changes: 120 additions & 0 deletions src/embedded/IterableActionRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
export enum IterableActionSource {
PUSH = 'PUSH',
APP_LINK = 'APP_LINK',
IN_APP = 'IN_APP',
EMBEDDED = 'EMBEDDED'
}

export interface IterableAction {
type: string;
data: string;
}

export interface IterableActionContext {
action: IterableAction;
source: IterableActionSource;
}

interface IterableConfig {
urlHandler?: {
handleIterableURL(
uri: string,
actionContext: IterableActionContext
): boolean;
};
customActionHandler?: {
handleIterableCustomAction(
action: IterableAction,
actionContext: IterableActionContext
): boolean;
};
}

class IterableActionRunnerConfig {
static config: IterableConfig = {};
}

class IterableActionRunnerImpl {

executeAction(
context: any,
action: IterableAction | null,
source: IterableActionSource
): boolean {
if (action === null) {
return false;
}

const actionContext: IterableActionContext = { action, source };

if (action.type === 'openUrl') {
return this.openUri(action.data, actionContext);
} else {
return this.callCustomActionIfSpecified(action, actionContext);
}
}

private openUri(uri: string, actionContext: IterableActionContext): boolean {
if (IterableActionRunnerConfig.config.urlHandler) {
if (
IterableActionRunnerConfig.config.urlHandler.handleIterableURL(
uri,
actionContext
)
) {
return true;
}
}

window.open(uri, '_blank');

return true;
}

private callCustomActionIfSpecified(
action: IterableAction,
actionContext: IterableActionContext
): boolean {
if (action.type && action.type !== '') {
if (IterableActionRunnerConfig.config.customActionHandler) {
return IterableActionRunnerConfig.config.customActionHandler.handleIterableCustomAction(
action,
actionContext
);
}
}
return false;
}
}

IterableActionRunnerConfig.config = {
urlHandler: {
handleIterableURL(
uri: string,
actionContext: IterableActionContext
): boolean {
global.open(uri, '_blank', 'noopener,noreferrer');
return true;
}
},
customActionHandler: {
handleIterableCustomAction(
action: IterableAction,
actionContext: IterableActionContext
): boolean {
let uri = '';
if (action.type.startsWith('action://')) {
uri = action.type.replace('action://', '');
} else if (action.type.startsWith('iterable://')) {
uri = action.type.replace('iterable://', '');
}

global.open(uri, '_blank', 'noopener,noreferrer');
return true;
}
}
};

export class IterableActionRunner extends IterableActionRunnerImpl {
static config = IterableActionRunnerConfig.config;
}
21 changes: 16 additions & 5 deletions src/embedded/embeddedManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,20 @@ export class EmbeddedManager {
url += placementIds.map((id) => `&placementIds=${id}`).join('');
}
url = url.replace(/&$/, '');

const iterableResult: any = await baseIterableRequest<IterableResponse>({
method: 'GET',
url: url
});
if (iterableResult?.data?.placements[0]?.embeddedMessages?.length) {
const embeddedMessages = this.getEmbeddedMessages(
iterableResult?.data?.placements || []
);
if (embeddedMessages.length) {
const processor = new EmbeddedMessagingProcessor(
[...this.messages],
this.getEmbeddedMessages(iterableResult?.data?.placements)
);
this.setMessages(processor);
await this.trackNewlyRetrieved(processor);
await this.trackNewlyRetrieved(processor, userIdOrEmail);
this.messages = [
...this.getEmbeddedMessages(iterableResult?.data?.placements)
];
Expand Down Expand Up @@ -106,10 +108,19 @@ export class EmbeddedManager {
});
}

private async trackNewlyRetrieved(_processor: EmbeddedMessagingProcessor) {
private async trackNewlyRetrieved(
_processor: EmbeddedMessagingProcessor,
userIdOrEmail: string
) {
const msgsList = _processor.newlyRetrievedMessages();
for (let i = 0; i < msgsList.length; i++) {
await trackEmbeddedMessageReceived(msgsList[i]);
const messages = {} as IEmbeddedMessage;
messages.messageId = msgsList[i].metadata.messageId;

functions.checkEmailValidation(userIdOrEmail)
? (messages.email = userIdOrEmail)
: (messages.userId = userIdOrEmail);
await trackEmbeddedMessageReceived(messages);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/embedded/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './embeddedManager';
export * from './types';
export * from './embeddedSessionManager';
export * from './embeddedMessage';
export * from './IterableActionRunner';
2 changes: 2 additions & 0 deletions src/events/embedded/events.schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { boolean, number, object, string, array, mixed, date } from 'yup';

export const trackEmbeddedMessageSchema = object().shape({
email: string(),
userId: string(),
metadata: object().shape({
messageId: string(),
campaignId: number(),
Expand Down
3 changes: 3 additions & 0 deletions src/events/embedded/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export interface IEmbeddedMessageElements {
}

export interface IEmbeddedMessage {
email?: string;
userId?: string;
messageId?: string;
metadata: IEmbeddedMessageMetadata;
elements?: IEmbeddedMessageElements;
payload?: Array<any>;
Expand Down

0 comments on commit 198ecf6

Please sign in to comment.