feat: Add flat design for widget (#4065)
This commit is contained in:
@@ -26,6 +26,7 @@ import { dispatchWindowEvent } from 'shared/helpers/CustomEventHelper';
|
||||
import { CHATWOOT_ERROR, CHATWOOT_READY } from '../widget/constants/sdkEvents';
|
||||
import { SET_USER_ERROR } from '../widget/constants/errorTypes';
|
||||
import { getUserCookieName } from './cookieHelpers';
|
||||
import { isFlatWidgetStyle } from './settingsHelper';
|
||||
|
||||
export const IFrameHelper = {
|
||||
getUrl({ baseUrl, websiteToken }) {
|
||||
@@ -52,6 +53,10 @@ export const IFrameHelper = {
|
||||
if (window.$chatwoot.hideMessageBubble) {
|
||||
holderClassName += ` woot-widget--without-bubble`;
|
||||
}
|
||||
if (isFlatWidgetStyle(window.$chatwoot.widgetStyle)) {
|
||||
holderClassName += ` woot-widget-holder--flat`;
|
||||
}
|
||||
|
||||
addClass(widgetHolder, holderClassName);
|
||||
widgetHolder.appendChild(iframe);
|
||||
body.appendChild(widgetHolder);
|
||||
@@ -121,6 +126,7 @@ export const IFrameHelper = {
|
||||
position: window.$chatwoot.position,
|
||||
hideMessageBubble: window.$chatwoot.hideMessageBubble,
|
||||
showPopoutButton: window.$chatwoot.showPopoutButton,
|
||||
widgetStyle: window.$chatwoot.widgetStyle,
|
||||
});
|
||||
IFrameHelper.onLoad({
|
||||
widgetColor: message.config.channelConfig.widgetColor,
|
||||
@@ -222,21 +228,27 @@ export const IFrameHelper = {
|
||||
createBubbleHolder();
|
||||
onLocationChangeListener();
|
||||
if (!window.$chatwoot.hideMessageBubble) {
|
||||
let className = 'woot-widget-bubble';
|
||||
let closeBtnClassName = `woot-elements--${window.$chatwoot.position} woot-widget-bubble woot--close woot--hide`;
|
||||
|
||||
if (isFlatWidgetStyle(window.$chatwoot.widgetStyle)) {
|
||||
className += ' woot-widget-bubble--flat';
|
||||
closeBtnClassName += ' woot-widget-bubble--flat';
|
||||
}
|
||||
|
||||
const chatIcon = createBubbleIcon({
|
||||
className: 'woot-widget-bubble',
|
||||
className,
|
||||
src: bubbleImg,
|
||||
target: chatBubble,
|
||||
});
|
||||
|
||||
const closeIcon = closeBubble;
|
||||
const closeIconclassName = `woot-elements--${window.$chatwoot.position} woot-widget-bubble woot--close woot--hide`;
|
||||
addClass(closeIcon, closeIconclassName);
|
||||
addClass(closeBubble, closeBtnClassName);
|
||||
|
||||
chatIcon.style.background = widgetColor;
|
||||
closeIcon.style.background = widgetColor;
|
||||
closeBubble.style.background = widgetColor;
|
||||
|
||||
bubbleHolder.appendChild(chatIcon);
|
||||
bubbleHolder.appendChild(closeIcon);
|
||||
bubbleHolder.appendChild(closeBubble);
|
||||
bubbleHolder.appendChild(createNotificationBubble());
|
||||
onClickChatBubble();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { addClass, removeClass, toggleClass, wootOn } from './DOMHelpers';
|
||||
import { IFrameHelper } from './IFrameHelper';
|
||||
import { BUBBLE_DESIGN } from './constants';
|
||||
import { isExpandedView } from './settingsHelper';
|
||||
|
||||
export const bubbleImg =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAAwgJEBk0TVheY2R5eo+ut8jb5OXs8fX2+cjRDTIAAADsSURBVHgBldZbkoMgFIThRgQv8SKKgGf/C51UnJqaRI30/9zfe+NQUQ3TvG7bOk9DVeCmshmj/CuOTYnrdBfkUOg0zlOtl9OWVuEk4+QyZ3DIevmSt/ioTvK1VH/s5bY3YdM9SBZ/mUUyWgx+U06ycgp7D8msxSvtc4HXL9BLdj2elSEfhBJAI0QNgJEBI1BEBsQClVBVGDgwYOLAhJkDM1YOrNg4sLFAsLJgZsHEgoEFFQt0JAFGFjQsKAMJ0LFAexKgZYFyJIDxJIBNJEDNAtSJBLCeBDCOBFAPzwFA94ED+zmhwDO9358r8ANtIsMXi7qVAwAAAABJRU5ErkJggg==';
|
||||
@@ -13,10 +13,6 @@ export const chatBubble = document.createElement('button');
|
||||
export const closeBubble = document.createElement('button');
|
||||
export const notificationBubble = document.createElement('span');
|
||||
|
||||
export const getBubbleView = type =>
|
||||
BUBBLE_DESIGN.includes(type) ? type : BUBBLE_DESIGN[0];
|
||||
export const isExpandedView = type => getBubbleView(type) === BUBBLE_DESIGN[1];
|
||||
|
||||
export const setBubbleText = bubbleText => {
|
||||
if (isExpandedView(window.$chatwoot.type)) {
|
||||
const textNode = document.getElementById('woot-widget--expanded__text');
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export const BUBBLE_DESIGN = ['standard', 'expanded_bubble'];
|
||||
export const WIDGET_DESIGN = ['standard', 'flat'];
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
import md5 from 'md5';
|
||||
|
||||
const REQUIRED_USER_KEYS = ['avatar_url', 'email', 'name'];
|
||||
const ALLOWED_USER_ATTRIBUTES = [...REQUIRED_USER_KEYS, 'identifier_hash'];
|
||||
|
||||
export const getUserCookieName = () => {
|
||||
const SET_USER_COOKIE_PREFIX = 'cw_user_';
|
||||
const { websiteToken: websiteIdentifier } = window.$chatwoot;
|
||||
return `${SET_USER_COOKIE_PREFIX}${websiteIdentifier}`;
|
||||
};
|
||||
|
||||
export const getUserString = ({ identifier = '', user }) => {
|
||||
const userStringWithSortedKeys = ALLOWED_USER_ATTRIBUTES.reduce(
|
||||
(acc, key) => `${acc}${key}${user[key] || ''}`,
|
||||
''
|
||||
);
|
||||
return `${userStringWithSortedKeys}identifier${identifier}`;
|
||||
};
|
||||
|
||||
export const computeHashForUserData = (...args) => md5(getUserString(...args));
|
||||
|
||||
export const hasUserKeys = user =>
|
||||
REQUIRED_USER_KEYS.reduce((acc, key) => acc || !!user[key], false);
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
export const SDK_CSS = `.woot-widget-holder {
|
||||
box-shadow: 0 5px 40px rgba(0, 0, 0, .16) !important;
|
||||
export const SDK_CSS = `
|
||||
:root {
|
||||
--b-100: #F2F3F7;
|
||||
}
|
||||
|
||||
.woot-widget-holder {
|
||||
box-shadow: 0 5px 40px rgba(0, 0, 0, .16);
|
||||
opacity: 1;
|
||||
will-change: transform, opacity;
|
||||
transform: translateY(0);
|
||||
@@ -9,6 +14,12 @@ export const SDK_CSS = `.woot-widget-holder {
|
||||
z-index: 2147483000 !important;
|
||||
}
|
||||
|
||||
.woot-widget-holder.woot-widget-holder--flat {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
border: 1px solid var(--b-100);
|
||||
}
|
||||
|
||||
.woot-widget-holder iframe {
|
||||
border: 0;
|
||||
height: 100% !important;
|
||||
@@ -22,21 +33,45 @@ export const SDK_CSS = `.woot-widget-holder {
|
||||
height: auto;
|
||||
bottom: 94px;
|
||||
box-shadow: none !important;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.woot-widget-bubble {
|
||||
background: #1f93ff;
|
||||
border-radius: 100px !important;
|
||||
border-radius: 100px;
|
||||
border-width: 0px;
|
||||
bottom: 20px;
|
||||
padding: 0px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, .16) !important;
|
||||
cursor: pointer;
|
||||
height: 64px !important;
|
||||
height: 64px;
|
||||
padding: 0px;
|
||||
position: fixed;
|
||||
width: 64px !important;
|
||||
z-index: 2147483000 !important;
|
||||
user-select: none;
|
||||
width: 64px;
|
||||
z-index: 2147483000 !important;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.woot-widget-bubble--flat {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.woot-widget-holder.woot-widget-holder--flat {
|
||||
bottom: 90px;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.woot-widget-bubble--flat {
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.woot-widget-bubble--flat img {
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.woot-widget-bubble--flat.woot--close::before,
|
||||
.woot-widget-bubble.woot-widget-bubble--flat.woot--close::after {
|
||||
left: 28px;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.woot-widget-bubble.unread-notification::after {
|
||||
@@ -184,7 +219,7 @@ export const SDK_CSS = `.woot-widget-holder {
|
||||
|
||||
@media only screen and (min-width: 667px) {
|
||||
.woot-widget-holder {
|
||||
border-radius: 16px !important;
|
||||
border-radius: 16px;
|
||||
bottom: 104px;
|
||||
height: calc(85% - 64px - 20px);
|
||||
max-height: 590px !important;
|
||||
|
||||
11
app/javascript/sdk/settingsHelper.js
Normal file
11
app/javascript/sdk/settingsHelper.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { BUBBLE_DESIGN, WIDGET_DESIGN } from './constants';
|
||||
|
||||
export const getBubbleView = type =>
|
||||
BUBBLE_DESIGN.includes(type) ? type : BUBBLE_DESIGN[0];
|
||||
|
||||
export const isExpandedView = type => getBubbleView(type) === BUBBLE_DESIGN[1];
|
||||
|
||||
export const getWidgetStyle = style =>
|
||||
WIDGET_DESIGN.includes(style) ? style : WIDGET_DESIGN[0];
|
||||
|
||||
export const isFlatWidgetStyle = style => style === 'flat';
|
||||
@@ -1,17 +0,0 @@
|
||||
import { getBubbleView, isExpandedView } from '../bubbleHelpers';
|
||||
|
||||
describe('#getBubbleView', () => {
|
||||
it('returns correct view', () => {
|
||||
expect(getBubbleView('')).toEqual('standard');
|
||||
expect(getBubbleView('standard')).toEqual('standard');
|
||||
expect(getBubbleView('expanded_bubble')).toEqual('expanded_bubble');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isExpandedView', () => {
|
||||
it('returns true if it is expanded view', () => {
|
||||
expect(isExpandedView('')).toEqual(false);
|
||||
expect(isExpandedView('standard')).toEqual(false);
|
||||
expect(isExpandedView('expanded_bubble')).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,8 @@
|
||||
import { getUserCookieName } from '../cookieHelpers';
|
||||
import {
|
||||
getUserCookieName,
|
||||
getUserString,
|
||||
hasUserKeys,
|
||||
} from '../cookieHelpers';
|
||||
|
||||
describe('#getUserCookieName', () => {
|
||||
it('returns correct cookie name', () => {
|
||||
@@ -6,3 +10,40 @@ describe('#getUserCookieName', () => {
|
||||
expect(getUserCookieName()).toBe('cw_user_123456');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getUserString', () => {
|
||||
it('returns correct user string', () => {
|
||||
expect(
|
||||
getUserString({
|
||||
user: {
|
||||
name: 'Pranav',
|
||||
email: 'pranav@example.com',
|
||||
avatar_url: 'https://images.chatwoot.com/placeholder',
|
||||
identifier_hash: '12345',
|
||||
},
|
||||
identifier: '12345',
|
||||
})
|
||||
).toBe(
|
||||
'avatar_urlhttps://images.chatwoot.com/placeholderemailpranav@example.comnamePranavidentifier_hash12345identifier12345'
|
||||
);
|
||||
|
||||
expect(
|
||||
getUserString({
|
||||
user: {
|
||||
email: 'pranav@example.com',
|
||||
avatar_url: 'https://images.chatwoot.com/placeholder',
|
||||
},
|
||||
})
|
||||
).toBe(
|
||||
'avatar_urlhttps://images.chatwoot.com/placeholderemailpranav@example.comnameidentifier_hashidentifier'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#hasUserKeys', () => {
|
||||
it('checks whether the allowed list of keys are present', () => {
|
||||
expect(hasUserKeys({})).toBe(false);
|
||||
expect(hasUserKeys({ randomKey: 'randomValue' })).toBe(false);
|
||||
expect(hasUserKeys({ avatar_url: 'randomValue' })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
38
app/javascript/sdk/specs/settingsHelpers.spec.js
Normal file
38
app/javascript/sdk/specs/settingsHelpers.spec.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
getBubbleView,
|
||||
getWidgetStyle,
|
||||
isExpandedView,
|
||||
isFlatWidgetStyle,
|
||||
} from '../settingsHelper';
|
||||
|
||||
describe('#getBubbleView', () => {
|
||||
it('returns correct view', () => {
|
||||
expect(getBubbleView('')).toEqual('standard');
|
||||
expect(getBubbleView('standard')).toEqual('standard');
|
||||
expect(getBubbleView('expanded_bubble')).toEqual('expanded_bubble');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isExpandedView', () => {
|
||||
it('returns true if it is expanded view', () => {
|
||||
expect(isExpandedView('')).toEqual(false);
|
||||
expect(isExpandedView('standard')).toEqual(false);
|
||||
expect(isExpandedView('expanded_bubble')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getWidgetStyle', () => {
|
||||
it('returns correct view', () => {
|
||||
expect(getWidgetStyle('')).toEqual('standard');
|
||||
expect(getWidgetStyle('standard')).toEqual('standard');
|
||||
expect(getWidgetStyle('flat')).toEqual('flat');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isFlatWidgetStyle', () => {
|
||||
it('returns true if it is expanded view', () => {
|
||||
expect(isFlatWidgetStyle('')).toEqual(false);
|
||||
expect(isFlatWidgetStyle('standard')).toEqual(false);
|
||||
expect(isFlatWidgetStyle('flat')).toEqual(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user