Skip to content

Commit a90c235

Browse files
committed
Refactor message data types into distinct folder
Export message types
1 parent 790ce1a commit a90c235

File tree

19 files changed

+359
-267
lines changed

19 files changed

+359
-267
lines changed

src/Sse.ts

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,63 @@
1-
// eslint-disable-next-line @typescript-eslint/no-namespace
2-
export namespace Sse {
3-
let sseIsEnabled = false;
4-
let eventSource: EventSource;
5-
let notInitialised: boolean;
1+
import { BotConnectorResponse } from './model/responses';
62

7-
export function init(
8-
tockEndPoint: string,
9-
userId: string,
10-
handleBotResponse: (botResponse: any) => void,
11-
onSseStateChange: (state: number) => void,
12-
): Promise<void> {
13-
return new Promise<void>((afterInit: () => void): void => {
14-
if (typeof EventSource !== 'undefined' && tockEndPoint && !eventSource) {
15-
notInitialised = true;
16-
eventSource = new EventSource(tockEndPoint + '/sse?userid=' + userId);
17-
setTimeout(() => onSseStateChange(eventSource.readyState));
18-
eventSource.addEventListener(
19-
'message',
20-
(e: MessageEvent) => {
21-
handleBotResponse(JSON.parse(e.data));
22-
},
23-
false,
24-
);
25-
eventSource.addEventListener(
26-
'open',
27-
() => {
3+
let sseIsEnabled = false;
4+
let eventSource: EventSource;
5+
let notInitialised: boolean;
6+
7+
export function init(
8+
tockEndPoint: string,
9+
userId: string,
10+
handleBotResponse: (botResponse: BotConnectorResponse) => void,
11+
onSseStateChange: (state: number) => void,
12+
): Promise<void> {
13+
return new Promise<void>((afterInit: () => void): void => {
14+
if (typeof EventSource !== 'undefined' && tockEndPoint && !eventSource) {
15+
notInitialised = true;
16+
eventSource = new EventSource(tockEndPoint + '/sse?userid=' + userId);
17+
setTimeout(() => onSseStateChange(eventSource.readyState));
18+
eventSource.addEventListener(
19+
'message',
20+
(e: MessageEvent) => {
21+
handleBotResponse(JSON.parse(e.data));
22+
},
23+
false,
24+
);
25+
eventSource.addEventListener(
26+
'open',
27+
() => {
28+
onSseStateChange(eventSource.readyState);
29+
sseIsEnabled = true;
30+
if (notInitialised) {
31+
afterInit();
32+
notInitialised = false;
33+
}
34+
},
35+
false,
36+
);
37+
eventSource.addEventListener(
38+
'error',
39+
() => {
40+
if (eventSource.readyState == EventSource.CLOSED) {
2841
onSseStateChange(eventSource.readyState);
29-
sseIsEnabled = true;
42+
sseIsEnabled = false;
3043
if (notInitialised) {
3144
afterInit();
3245
notInitialised = false;
3346
}
34-
},
35-
false,
36-
);
37-
eventSource.addEventListener(
38-
'error',
39-
() => {
40-
if (eventSource.readyState == EventSource.CLOSED) {
41-
onSseStateChange(eventSource.readyState);
42-
sseIsEnabled = false;
43-
if (notInitialised) {
44-
afterInit();
45-
notInitialised = false;
46-
}
47-
}
48-
},
49-
false,
50-
);
51-
}
52-
});
53-
}
47+
}
48+
},
49+
false,
50+
);
51+
}
52+
});
53+
}
5454

55-
export function isEnable(): boolean {
56-
return sseIsEnabled;
57-
}
55+
export function isEnable(): boolean {
56+
return sseIsEnabled;
57+
}
5858

59-
export function disable(): Promise<void> {
60-
sseIsEnabled = false;
61-
notInitialised = false;
62-
return Promise.resolve();
63-
}
59+
export function disable(): Promise<void> {
60+
sseIsEnabled = false;
61+
notInitialised = false;
62+
return Promise.resolve();
6463
}

src/TockContext.tsx

Lines changed: 10 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import React, {
2+
Context,
3+
createContext,
24
Dispatch,
35
ReactNode,
46
Reducer,
5-
useReducer,
6-
createContext,
7-
Context,
87
useContext,
8+
useReducer,
99
} from 'react';
1010
import { retrieveUserId } from './utils';
11+
import { QuickReply } from './model/buttons';
12+
import { Message } from './model/messages';
1113

12-
export const TockStateContext: Context<TockState | undefined> = createContext<
14+
const TockStateContext: Context<TockState | undefined> = createContext<
1315
TockState | undefined
1416
>(undefined);
15-
export const TockStateDispatch: Context<
17+
const TockStateDispatch: Context<
1618
Dispatch<TockAction> | undefined
1719
> = createContext<Dispatch<TockAction> | undefined>(undefined);
1820

@@ -34,107 +36,9 @@ export const useTockDispatch: () => Dispatch<TockAction> = () => {
3436
return dispatch;
3537
};
3638

37-
export class QuickReply {
38-
label: string;
39-
payload?: string;
40-
nlpText?: string;
41-
imageUrl?: string;
42-
43-
constructor(
44-
label: string,
45-
payload: string,
46-
nlpText?: string,
47-
imageUrl?: string,
48-
) {
49-
this.label = label;
50-
this.payload = payload;
51-
this.nlpText = nlpText;
52-
this.imageUrl = imageUrl;
53-
}
54-
}
55-
56-
export class PostBackButton {
57-
label: string;
58-
payload?: string;
59-
imageUrl?: string;
60-
61-
constructor(label: string, payload: string, imageUrl?: string) {
62-
this.label = label;
63-
this.payload = payload;
64-
this.imageUrl = imageUrl;
65-
}
66-
}
67-
68-
export class UrlButton {
69-
label: string;
70-
url: string;
71-
imageUrl?: string;
72-
73-
constructor(label: string, url: string, imageUrl?: string) {
74-
this.label = label;
75-
this.url = url;
76-
this.imageUrl = imageUrl;
77-
}
78-
}
79-
80-
export type Button = QuickReply | PostBackButton | UrlButton;
81-
82-
export type Messages = Message | Card | Carousel | Widget | Image;
83-
84-
export enum MessageType {
85-
message = 'message',
86-
card = 'card',
87-
carousel = 'carousel',
88-
widget = 'widget',
89-
image = 'image',
90-
}
91-
92-
export interface Message {
93-
type: MessageType;
94-
alreadyDisplayed?: boolean;
95-
}
96-
97-
export interface TextMessage extends Message {
98-
author: 'bot' | 'user';
99-
message: string;
100-
type: MessageType.message;
101-
buttons?: Button[];
102-
}
103-
104-
export interface Card extends Message {
105-
imageUrl?: string;
106-
imageAlternative?: string;
107-
title: string;
108-
subTitle?: string;
109-
buttons?: Button[];
110-
type: MessageType.card;
111-
}
112-
113-
export interface Carousel extends Message {
114-
cards: Card[];
115-
type: MessageType.carousel;
116-
}
117-
118-
export interface Widget extends Message {
119-
widgetData: WidgetData;
120-
type: MessageType.widget;
121-
}
122-
123-
export interface WidgetData {
124-
data: any;
125-
type: string;
126-
}
127-
128-
export interface Image extends Message {
129-
url?: string;
130-
title: string;
131-
type: MessageType.image;
132-
alternative?: string;
133-
}
134-
13539
export interface TockState {
13640
quickReplies: QuickReply[];
137-
messages: Messages[];
41+
messages: Message[];
13842
userId: string;
13943
loading: boolean;
14044
sseInitializing: boolean;
@@ -148,12 +52,12 @@ export interface TockAction {
14852
| 'SET_SSE_INITIALIZING'
14953
| 'CLEAR_MESSAGES';
15054
quickReplies?: QuickReply[];
151-
messages?: Messages[];
55+
messages?: Message[];
15256
loading?: boolean;
15357
sseInitializing?: boolean;
15458
}
15559

156-
export const tockReducer: Reducer<TockState, TockAction> = (
60+
const tockReducer: Reducer<TockState, TockAction> = (
15761
state: TockState,
15862
action: TockAction,
15963
): TockState => {

src/components/Card/Card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import React, {
66
} from 'react';
77
import { prop } from 'styled-tools';
88

9-
import { Button as ButtonData } from '../../TockContext';
9+
import { Button as ButtonData } from '../../model/buttons';
1010
import '../../styles/theme';
1111

1212
export const CardOuter: StyledComponent<DetailedHTMLProps<

src/components/Carousel/Carousel.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
22

33
import React from 'react';
44
import { action } from '@storybook/addon-actions';
5-
import { UrlButton } from '../../TockContext';
5+
import { UrlButton } from '../../model/buttons';
66
import Carousel from './Carousel';
77
import Card, { CardProps } from '../Card';
88

src/components/Conversation/Conversation.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { useEffect } from 'react';
44
import React from 'react';
55

66
import useTock, { UseTock } from '../../useTock';
7-
import { MessageType, PostBackButton, UrlButton } from '../../TockContext';
7+
import { PostBackButton, UrlButton } from '../../model/buttons';
8+
import { MessageType } from '../../model/messages';
89
import Product from '../widgets/ProductWidget/Product';
910
import Conversation from './Conversation';
1011

src/components/Conversation/Conversation.tsx

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { DetailedHTMLProps, HTMLAttributes } from 'react';
22
import styled from '@emotion/styled';
3+
import { useTheme } from '@emotion/react';
34

45
import DefaultWidget from '../widgets/DefaultWidget';
56
import MessageBot from '../MessageBot';
@@ -12,22 +13,19 @@ import QuickReplyList from '../QuickReplyList';
1213
import InlineQuickReplyList from '../InlineQuickReplyList';
1314
import useMessageCounter from './hooks/useMessageCounter';
1415
import useScrollBehaviour from './hooks/useScrollBehaviour';
15-
import { useTheme } from '@emotion/react';
16-
import '../../styles/theme';
1716
import TockTheme from '../../styles/theme';
1817

18+
import TockAccessibility from '../../TockAccessibility';
19+
import { Button, QuickReply } from '../../model/buttons';
1920
import type {
20-
Button,
2121
Card as ICard,
2222
Carousel as ICarousel,
23-
Message,
2423
Image as IImage,
24+
Message,
2525
MessageType,
2626
TextMessage,
2727
Widget,
28-
QuickReply as CQuickReply,
29-
} from 'TockContext';
30-
import TockAccessibility from 'TockAccessibility';
28+
} from '../../model/messages';
3129

3230
const ConversationOuterContainer = styled.div`
3331
display: flex;
@@ -52,9 +50,10 @@ interface RenderOptions {
5250
onAction: (button: Button) => void;
5351
}
5452

55-
const renderWidget = (message: Widget, options: RenderOptions) => {
56-
const Widget = options?.widgets[message.widgetData.type] ?? DefaultWidget;
57-
return <Widget {...message.widgetData.data} />;
53+
const renderWidget = (widget: Widget, options: RenderOptions) => {
54+
const WidgetRenderer =
55+
options.widgets?.[widget.widgetData.type] ?? DefaultWidget;
56+
return <WidgetRenderer {...widget.widgetData.data} />;
5857
};
5958

6059
const renderMessage = (message: TextMessage, options: RenderOptions) => {
@@ -105,7 +104,7 @@ const MESSAGE_RENDERER: {
105104
const makeRenderMessage = (
106105
options: RenderOptions,
107106
accessibility?: TockAccessibility,
108-
) => (message: Message | ICard | ICarousel | Widget, index: number) => {
107+
) => (message: Message, index: number) => {
109108
const render: Renderer = MESSAGE_RENDERER[message.type];
110109
if (!render) return null;
111110
return React.cloneElement(render(message, options, accessibility), {
@@ -121,7 +120,7 @@ type Props = DetailedHTMLProps<
121120
messageDelay: number;
122121
widgets?: { [id: string]: (props: unknown) => JSX.Element };
123122
loading?: boolean;
124-
quickReplies: CQuickReply[];
123+
quickReplies: QuickReply[];
125124
onAction: (button: Button) => void;
126125
onQuickReplyClick: (button: Button) => void;
127126
accessibility?: TockAccessibility;
@@ -164,21 +163,18 @@ const Conversation = ({
164163
</ConversationInnerContainer>
165164
{!loading &&
166165
displayableMessageCount === messages.length &&
167-
theme.inlineQuickReplies !== true && (
168-
<QuickReplyList
166+
(theme.inlineQuickReplies ? (
167+
<InlineQuickReplyList
169168
items={quickReplies}
170169
onItemClick={onQuickReplyClick}
170+
accessibility={accessibility}
171171
/>
172-
)}
173-
{!loading &&
174-
displayableMessageCount === messages.length &&
175-
theme.inlineQuickReplies === true && (
176-
<InlineQuickReplyList
172+
) : (
173+
<QuickReplyList
177174
items={quickReplies}
178175
onItemClick={onQuickReplyClick}
179-
accessibility={accessibility}
180176
/>
181-
)}
177+
))}
182178
</ConversationOuterContainer>
183179
);
184180
} else {

src/components/Conversation/hooks/useMessageCounter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect } from 'react';
2-
import { Message } from '../../../TockContext';
2+
import { Message } from '../../../model/messages';
33

44
export default function useMessageCounter(
55
messages: Message[],

0 commit comments

Comments
 (0)