Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/Sse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export namespace Sse {
let sseIsEnabled = false;
let eventSource: EventSource;

export function init(tockEndPoint: string, userId: string, handleBotResponse: (botResponse: any) => void) {
if (typeof (EventSource) !== "undefined" && tockEndPoint && !eventSource) {
eventSource = new EventSource(tockEndPoint + '/sse?userid=' + userId);
eventSource.addEventListener('message', (e: MessageEvent) => {
handleBotResponse(JSON.parse(e.data))
}, false);
eventSource.addEventListener('open', (e: Event) => {
sseIsEnabled = true;
}, false);
eventSource.addEventListener('error', (e: Event) => {
// @ts-ignore
if (e.readyState == EventSource.CLOSED) {
sseIsEnabled = false;
}
}, false);
}
}

export function isEnable(): boolean {
return sseIsEnabled
}
}
14 changes: 12 additions & 2 deletions src/TockContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,14 @@ export interface TockState {
quickReplies: QuickReply[];
messages: (Message | Card | Carousel | Widget)[];
userId: string;
loading: boolean;
}

export interface TockAction {
type: 'SET_QUICKREPLIES' | 'ADD_MESSAGE';
type: 'SET_QUICKREPLIES' | 'ADD_MESSAGE' | 'SET_LOADING';
quickReplies?: QuickReply[];
messages?: (Message | Card | Carousel | Widget)[];
loading?: boolean;
}

export const tockReducer: Reducer<TockState, TockAction> = (
Expand All @@ -96,6 +98,13 @@ export const tockReducer: Reducer<TockState, TockAction> = (
messages: [...state.messages, ...action.messages],
};
}
case 'SET_LOADING':
if (action.loading != undefined) {
return {
...state,
loading: action.loading
}
}
default:
break;
}
Expand All @@ -110,7 +119,8 @@ const TockContext: (props: { children?: ReactNode }) => JSX.Element = ({
const [state, dispatch]: [TockState, Dispatch<TockAction>] = useReducer(tockReducer, {
quickReplies: [],
messages: [],
userId: (Date.now().toString(36) + Math.random().toString(36).substr(2, 5)).toUpperCase()
userId: (Date.now().toString(36) + Math.random().toString(36).substr(2, 5)).toUpperCase(),
loading: false
});
return (
<TockStateContext.Provider value={state}>
Expand Down
1 change: 1 addition & 0 deletions src/TockTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface TockTheme {
inputColor?: string;
borderRadius?: string;
conversationWidth?: string;
loaderSize?: string,
Comment thread
Tiska marked this conversation as resolved.
styles?: {
card?: TockThemeCardStyle;
carouselContainer?: string;
Expand Down
4 changes: 2 additions & 2 deletions src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface ChatProps {
}

const Chat: (props: ChatProps) => JSX.Element = ({endPoint, referralParameter, timeoutBetweenMessage = 700, widgets = {}}: ChatProps) => {
const {messages, quickReplies, sendMessage, sendQuickReply, sendAction, sendReferralParameter}: UseTock = useTock(
const {messages, quickReplies, loading, sendMessage, sendQuickReply, sendAction, sendReferralParameter}: UseTock = useTock(
endPoint
);
const [displayableMessageCount, setDisplayableMessageCount] = useState(0);
Expand All @@ -40,7 +40,6 @@ const Chat: (props: ChatProps) => JSX.Element = ({endPoint, referralParameter, t
return (
<Container>
<Conversation>
{referralParameter && displayableMessageCount == 0 && <Loader/>}
{messages.slice(0, displayableMessageCount).map((message: Message | Card | Carousel | Widget, i: number) => {
if (message.type === 'widget') {
let WidgetComponent = DefaultWidget;
Expand Down Expand Up @@ -81,6 +80,7 @@ const Chat: (props: ChatProps) => JSX.Element = ({endPoint, referralParameter, t
}
return null;
})}
{loading && <Loader/>}
</Conversation>
{displayableMessageCount == messages.length && <QuickReplyList>
{quickReplies.map((qr: QuickReply, i: number) => (
Expand Down
2 changes: 1 addition & 1 deletion src/components/Container/Container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const Container: StyledComponent<
}

& > *:not(:first-child) {
flex: 0;
flex: unset;
Comment thread
Tiska marked this conversation as resolved.
}

& * {
Expand Down
35 changes: 25 additions & 10 deletions src/components/Loader/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,29 @@ import {css, keyframes} from "@emotion/core";
import {Keyframes} from "@emotion/serialize";
import TockTheme from 'TockTheme';

const LoaderContainer: StyledComponent<
DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
const LoaderContainer: StyledComponent<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>,
{},
TockTheme
> = styled.div`
TockTheme> = styled.div`
width: 100%;
max-width: ${props => (props.theme && props.theme.conversationWidth) || '720px'};
margin: 0.5em auto;
`;

const BulletList: StyledComponent<{}, {}, TockTheme> = styled.div`
display: inline-block;
color: ${props => readableColor((props.theme && props.theme.botColor) || 'black')};
padding: 0.5em 1.5em;
margin-left: 1em;
white-space: pre-line;
border-radius: ${props =>
(props.theme &&
props.theme.borderRadius &&
`${props.theme.borderRadius} ${props.theme.borderRadius} ${props.theme.borderRadius} 0`) ||
'1em'};

${props => (props.theme && props.theme.styles && props.theme.styles.messageBot) || ''}
`;

const beat: Keyframes = keyframes`
50% {transform: scale(0.75);opacity: 0.2}
100% {transform: scale(1);opacity: 1}
Expand All @@ -24,9 +37,9 @@ const Bullet: StyledComponent<{}, {}, TockTheme> = styled.div(props => (
css`
display: inline-block;
background-color: ${readableColor((props.theme && props.theme.botColor) || 'black')};
width: ${props.theme.fontSize};
height: ${props.theme.fontSize};
margin: 0.5em;
width: ${props.theme.loaderSize || '8px'};
height: ${props.theme.loaderSize || '8px'};
margin: 0.5em 0.5em 0.5em 0;
border-radius: 100%;
animation: ${beat} 0.7s linear ${props["data-rank"] % 2 ? "0s" : "0.35s"} infinite normal both running;
`
Expand All @@ -35,9 +48,11 @@ const Bullet: StyledComponent<{}, {}, TockTheme> = styled.div(props => (
const Loader = () => {
return (
<LoaderContainer>
<Bullet data-rank={1} />
<Bullet data-rank={2} />
<Bullet data-rank={3} />
<BulletList>
<Bullet data-rank={1}/>
<Bullet data-rank={2}/>
<Bullet data-rank={3}/>
</BulletList>
</LoaderContainer>
);
};
Expand Down
61 changes: 48 additions & 13 deletions src/useTock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
Card,
Carousel, Widget, WidgetData,
} from './TockContext';
import { Sse } from "./Sse";

export interface UseTock {
messages: (Message | Card | Carousel | Widget)[];
quickReplies: QuickReply[];
loading: boolean;
addMessage: (message: string, author: 'bot' | 'user') => void;
sendMessage: (message: string) => Promise<void>;
addCard: (
Expand All @@ -29,18 +31,25 @@ export interface UseTock {
sendReferralParameter: (referralParameter: string) => Promise<void>;
}



const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
const { messages, quickReplies, userId }: TockState = useTockState();
const { messages, quickReplies, userId, loading }: TockState = useTockState();
const dispatch: Dispatch<TockAction> = useTockDispatch();

const addMessage: (message: string, author: 'bot' | 'user') => void = useCallback(
(message: string, author: 'bot' | 'user') =>
dispatch({
type: 'ADD_MESSAGE',
messages: [{ author, message, type: 'message' }],
}),
[]
);
const startLoading: () => void = () => {
dispatch({
type: 'SET_LOADING',
loading: true,
});
};

const stopLoading: () => void = () => {
dispatch({
type: 'SET_LOADING',
loading: false,
});
};

const handleBotResponse: (botResponse: any) => void = ({ responses }: any) => {
if (Array.isArray(responses) && responses.length > 0) {
Expand Down Expand Up @@ -107,11 +116,27 @@ const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
}
};

const handleBotResponseIfSseDisabled: (botResponse: any) => void = (botResponse: any) => {
if (!Sse.isEnable()) {
handleBotResponse(botResponse)
}
};

const addMessage: (message: string, author: 'bot' | 'user') => void = useCallback(
(message: string, author: 'bot' | 'user') =>
dispatch({
type: 'ADD_MESSAGE',
messages: [{author, message, type: 'message'}],
}),
[]
);

const sendMessage: (message: string) => Promise<void> = useCallback((message: string) => {
dispatch({
type: 'ADD_MESSAGE',
messages: [{ author: 'user', message, type: 'message' }],
});
startLoading();
return fetch(tockEndPoint, {
body: JSON.stringify({
query: message,
Expand All @@ -123,10 +148,12 @@ const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
},
})
.then(res => res.json())
.then(handleBotResponse);
.then(handleBotResponseIfSseDisabled)
.finally(stopLoading);
}, []);

const sendReferralParameter: (referralParameter: string) => Promise<void> = useCallback((referralParameter: string) => {
startLoading();
return fetch(tockEndPoint, {
body: JSON.stringify({
ref: referralParameter,
Expand All @@ -137,16 +164,19 @@ const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
'Content-Type': 'application/json',
},
})
.then(res => res.json())
.then(handleBotResponse);
.then(res => res.json())
.then(handleBotResponseIfSseDisabled)
.finally(stopLoading);
}, []);

const sendQuickReply: (label: string, payload?: string) => Promise<void> = (
label: string,
payload?: string
) => {
if (payload) {
setQuickReplies([]);
addMessage(label, 'user');
startLoading();
return fetch(tockEndPoint, {
body: JSON.stringify({
payload,
Expand All @@ -158,7 +188,8 @@ const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
},
})
.then(res => res.json())
.then(handleBotResponse);
.then(handleBotResponseIfSseDisabled)
.finally(stopLoading);
} else {
return sendMessage(label);
}
Expand Down Expand Up @@ -241,9 +272,13 @@ const useTock: (tockEndPoint: string) => UseTock = (tockEndPoint: string) => {
[]
);


Sse.init(tockEndPoint, userId, handleBotResponse);

return {
messages,
quickReplies,
loading,
addCard,
addCarousel,
addMessage,
Expand Down