Skip to content

Commit 6961357

Browse files
iamavishkarvishal753devcsomnicgmprew97Brad Umbaugh
authored
banner view implemented (Iterable#213)
* banner view implemented * code changes as per recent review * usage of banner view * Banner View Webpack config changed * .babelrc config changed * [MOB-7175]: add new filter method that leaves in JSON only messages (Iterable#238) * add new filter method that leaves in JSON only messages * Mentioning filterOnlyReadAndNeverTriggerMessages --------- Co-authored-by: mitch prewitt <[email protected]> Co-authored-by: Brad Umbaugh <[email protected]> * ver bump (Iterable#240) Co-authored-by: mitch prewitt <[email protected]> --------- Co-authored-by: Vishal Joshi <[email protected]> Co-authored-by: devcsomnicg <[email protected]> Co-authored-by: Mitch Prewitt <[email protected]> Co-authored-by: mitch prewitt <[email protected]> Co-authored-by: Brad Umbaugh <[email protected]> Co-authored-by: Hani <[email protected]>
1 parent 8f38c6a commit 6961357

File tree

8 files changed

+230
-3
lines changed

8 files changed

+230
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ request()
204204

205205
:rotating_light: *_PLEASE NOTE_*: If you choose the `deferred` option, the SDK will _not_ do any filtering or sorting on the messages internally. You will get the messages exactly as they come down from the API, untouched. This means you may (for example) show in-app messages marked `read` or show the messages in the wrong order based on `priority`.
206206

207-
If you want to keep the default sorting and filtering, please take advantage of the `sortInAppMessages` and `filterHiddenInAppMessages` methods the SDK provides.
207+
If you want to keep the default sorting and filtering, please take advantage of the `sortInAppMessages` and `filterHiddenInAppMessages` methods the SDK provides. Also see `filterOnlyReadAndNeverTriggerMessages`, which is similar to `filterHiddenInAppMessages` but does not filter out JSON-only messages.
208208

209209
## initialize
210210

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@iterable/web-sdk",
33
"description": "Iterable SDK for JavaScript and Node.",
4-
"version": "1.0.5",
4+
"version": "1.0.6",
55
"homepage": "https://iterable.com/",
66
"repository": {
77
"type": "git",

react-example/src/views/Banner.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Banner } from '@iterable/web-sdk';
2+
3+
export const BannerView = () => {
4+
return (
5+
<Banner
6+
body="Hello World!"
7+
buttonText="OK"
8+
heading="A banner view interface"
9+
logo="https://www.google.com/images/branding/googlelogo/1x/googlelogo_dark_color_272x92dp.png"
10+
/>
11+
);
12+
};
13+
14+
export default BannerView;

src/components/banner/index.tsx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import React, { CSSProperties } from 'react';
2+
import '../style.css';
3+
4+
interface IBannerProps {
5+
heading: string;
6+
body: string;
7+
buttonText: string;
8+
logo: string;
9+
buttonStyles?: CSSProperties;
10+
bannerStyles?: CSSProperties;
11+
logoStyles?: CSSProperties;
12+
headingStyles?: CSSProperties;
13+
bodyStyles?: CSSProperties;
14+
buttonClickHandler?: (e: any) => void;
15+
}
16+
17+
export const Banner = (props: IBannerProps) => {
18+
const {
19+
heading,
20+
body,
21+
buttonText,
22+
logo,
23+
bannerStyles,
24+
buttonStyles,
25+
logoStyles,
26+
headingStyles,
27+
bodyStyles,
28+
buttonClickHandler
29+
} = props;
30+
31+
const defaultBannerStyles = {
32+
display: 'flex',
33+
alignItems: 'center',
34+
backgroundColor: '#ffffff',
35+
padding: '20px',
36+
margin: '20px',
37+
borderRadius: '8px',
38+
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)'
39+
};
40+
const defaultHeadingStyles = {
41+
fontSize: '25px',
42+
marginBottom: '20px',
43+
marginRight: '20px'
44+
};
45+
const defaultBodyStyles = {
46+
fontSize: '16px',
47+
marginBottom: '20px',
48+
marginRight: '20px'
49+
};
50+
const defaultButtonStyles = {
51+
backgroundColor: '#6c016cf5',
52+
color: '#fff',
53+
padding: '10px 20px',
54+
border: 'none',
55+
borderRadius: '40px',
56+
cursor: 'pointer',
57+
marginBottom: '20px'
58+
};
59+
const defaultLogoStyles = {
60+
width: '100%',
61+
height: 'auto'
62+
};
63+
64+
return (
65+
<div
66+
className="banner-container"
67+
style={{ ...defaultBannerStyles, ...bannerStyles }}
68+
>
69+
<div className="content-container ">
70+
<h2 style={{ ...defaultHeadingStyles, ...headingStyles }}>{heading}</h2>
71+
<p style={{ ...defaultBodyStyles, ...bodyStyles }}>{body}</p>
72+
<button
73+
style={{ ...defaultButtonStyles, ...buttonStyles }}
74+
onClick={
75+
buttonClickHandler as React.MouseEventHandler<HTMLButtonElement>
76+
}
77+
>
78+
{buttonText}
79+
</button>
80+
</div>
81+
<div style={{ marginRight: '20px' }}>
82+
<img
83+
src={logo}
84+
alt="Logo"
85+
style={{ ...defaultLogoStyles, ...logoStyles }}
86+
/>
87+
</div>
88+
</div>
89+
);
90+
};

src/components/style.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
@media (max-width: 600px) {
2+
.banner-container {
3+
flex-direction: column;
4+
align-items: center;
5+
justify-content: center;
6+
}
7+
8+
.banner-container>.content-container {
9+
margin-bottom: 20px;
10+
order: 2;
11+
max-width: 75%;
12+
}
13+
14+
.banner-container>div:last-child {
15+
order: 1;
16+
margin-bottom: 0;
17+
}
18+
}
19+
120
@media (max-width: 768px) {
221
.card {
322
max-width: 90%;

src/inapp/tests/utils.test.ts

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { CLOSE_BUTTON_POSITION, CachedMessage, InAppMessage } from '../types';
99
import {
1010
addButtonAttrsToAnchorTag,
1111
filterHiddenInAppMessages,
12+
filterOnlyReadAndNeverTriggerMessages,
1213
generateCloseButton,
1314
generateWidth,
1415
getCachedMessagesToDelete,
@@ -33,7 +34,7 @@ const mockMarkup = `
3334
`;
3435

3536
describe('Utils', () => {
36-
describe('Filtering', () => {
37+
describe('filterHiddenInAppMessages', () => {
3738
it('should filter out read messages', () => {
3839
expect(filterHiddenInAppMessages()).toEqual([]);
3940
expect(filterHiddenInAppMessages(messages).every((e) => !e?.read)).toBe(
@@ -128,6 +129,100 @@ describe('Utils', () => {
128129
});
129130
});
130131

132+
describe('filterOnlyReadAndNeverTriggerMessages', () => {
133+
it('should filter out read messages', () => {
134+
expect(filterOnlyReadAndNeverTriggerMessages()).toEqual([]);
135+
expect(
136+
filterOnlyReadAndNeverTriggerMessages(messages).every((e) => !e?.read)
137+
).toBe(true);
138+
expect(
139+
filterOnlyReadAndNeverTriggerMessages([
140+
{
141+
...messages[0],
142+
read: true
143+
},
144+
{
145+
...messages[1],
146+
read: true
147+
}
148+
]).length
149+
).toBe(0);
150+
expect(
151+
filterOnlyReadAndNeverTriggerMessages([
152+
{
153+
...messages[0],
154+
trigger: { type: 'good' },
155+
read: undefined
156+
},
157+
{
158+
...messages[1],
159+
trigger: { type: 'good' },
160+
read: undefined
161+
}
162+
]).length
163+
).toBe(2);
164+
});
165+
166+
it('should filter out trigger type "never" messages', () => {
167+
expect(
168+
filterOnlyReadAndNeverTriggerMessages(messages).every(
169+
(e) => !e?.trigger?.type
170+
)
171+
).not.toBe('never');
172+
expect(
173+
filterOnlyReadAndNeverTriggerMessages([
174+
{
175+
...messages[0],
176+
trigger: { type: 'never' }
177+
},
178+
{
179+
...messages[1],
180+
trigger: { type: 'never' }
181+
}
182+
]).length
183+
).toBe(0);
184+
expect(
185+
filterOnlyReadAndNeverTriggerMessages([
186+
{
187+
...messages[0],
188+
trigger: undefined
189+
},
190+
{
191+
...messages[1],
192+
trigger: undefined
193+
}
194+
]).length
195+
).toBe(2);
196+
});
197+
198+
it('should not filter out messages with no HTML body', () => {
199+
expect(
200+
filterOnlyReadAndNeverTriggerMessages([
201+
{
202+
...messages[0],
203+
content: { ...messages[0].content, html: '' }
204+
},
205+
{
206+
...messages[1],
207+
content: { ...messages[0].content, html: '<p>' }
208+
}
209+
]).length
210+
).toBe(2);
211+
expect(
212+
filterOnlyReadAndNeverTriggerMessages([
213+
{
214+
...messages[0],
215+
content: undefined
216+
},
217+
{
218+
...messages[1],
219+
content: undefined
220+
}
221+
]).length
222+
).toBe(2);
223+
});
224+
});
225+
131226
describe('Sorting', () => {
132227
it('should sort messages by priority level, lesser ones first', () => {
133228
expect(sortInAppMessages()).toEqual([]);

src/inapp/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ export const filterHiddenInAppMessages = (
120120
});
121121
};
122122

123+
export const filterOnlyReadAndNeverTriggerMessages = (
124+
messages: Partial<InAppMessage>[] = []
125+
) => {
126+
return messages.filter(
127+
(eachMessage) => !eachMessage.read && eachMessage.trigger?.type !== 'never'
128+
);
129+
};
130+
123131
export const sortInAppMessages = (messages: Partial<InAppMessage>[] = []) => {
124132
return messages.sort(by(['priorityLevel', 'asc'], ['createdAt', 'asc']));
125133
};

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ export * from './types';
77
export * from './components/card';
88
export * from './embedded';
99
export * from './embedded';
10+
export * from './components/banner';
1011
export * from './components/notification';
1112
export { config } from './utils/config';

0 commit comments

Comments
 (0)