Skip to content

Commit 4dcd603

Browse files
committed
add function option to trigger
1 parent a8fdba1 commit 4dcd603

File tree

13 files changed

+91
-42
lines changed

13 files changed

+91
-42
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
localStorage: true,
99
},
1010
"rules": {
11+
"guard-for-in": ["off"],
1112
"no-console": ["off"],
1213
"no-use-before-define": ["off"],
1314
"no-restricted-syntax": ["off"],

dist/react-simple-chatbot.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ChatBot.jsx

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class ChatBot extends Component {
3939
};
4040

4141
this.renderStep = this.renderStep.bind(this);
42+
this.getTriggeredStep = this.getTriggeredStep.bind(this);
43+
this.generateRenderedStepsById = this.generateRenderedStepsById.bind(this);
4244
this.triggerNextStep = this.triggerNextStep.bind(this);
4345
this.onValueChange = this.onValueChange.bind(this);
4446
this.handleKeyPress = this.handleKeyPress.bind(this);
@@ -82,6 +84,14 @@ class ChatBot extends Component {
8284

8385
schema.checkInvalidIds(steps);
8486

87+
const firstStep = this.props.steps[0];
88+
89+
if (firstStep.message) {
90+
const message = firstStep.message;
91+
firstStep.message = typeof message === 'function' ? message() : message;
92+
steps[firstStep.id].message = firstStep.message;
93+
}
94+
8595
const {
8696
currentStep,
8797
previousStep,
@@ -90,7 +100,7 @@ class ChatBot extends Component {
90100
} = storage.getData({
91101
cacheName,
92102
cache,
93-
firstStep: this.props.steps[0],
103+
firstStep,
94104
steps,
95105
}, () => {
96106
// focus input if last step cached is a user step
@@ -133,6 +143,31 @@ class ChatBot extends Component {
133143
this.setState({ inputValue: event.target.value });
134144
}
135145

146+
getTriggeredStep(trigger, value) {
147+
const steps = this.generateRenderedStepsById();
148+
return (typeof trigger === 'function') ? trigger({ value, steps }) : trigger;
149+
}
150+
151+
getStepMessage(message) {
152+
const { previousSteps } = this.state;
153+
const lastStepIndex = previousSteps.length > 0 ? previousSteps.length - 1 : 0;
154+
const steps = this.generateRenderedStepsById();
155+
const previousValue = previousSteps[lastStepIndex].value;
156+
return (typeof message === 'function') ? message({ previousValue, steps }) : message;
157+
}
158+
159+
generateRenderedStepsById() {
160+
const { previousSteps } = this.state;
161+
const steps = {};
162+
163+
for (let i = 0, len = previousSteps.length; i < len; i += 1) {
164+
const { id, message, value } = previousSteps[i];
165+
steps[id] = { id, message, value };
166+
}
167+
168+
return steps;
169+
}
170+
136171
triggerNextStep(data) {
137172
const {
138173
defaultUserSettings,
@@ -147,13 +182,14 @@ class ChatBot extends Component {
147182
currentStep.value = data.value;
148183
}
149184
if (data && data.trigger) {
150-
currentStep.trigger = data.trigger;
185+
currentStep.trigger = this.getTriggeredStep(data.trigger, data.value);
151186
}
152187

153188
if (isEnd) {
154189
this.handleEnd();
155190
} else if (currentStep.options && data) {
156191
const option = currentStep.options.filter(o => o.value === data.value)[0];
192+
const trigger = this.getTriggeredStep(option.trigger, currentStep.value);
157193
delete currentStep.options;
158194

159195
// replace choose option for user message
@@ -164,8 +200,8 @@ class ChatBot extends Component {
164200
defaultUserSettings,
165201
{
166202
user: true,
167-
trigger: option.trigger,
168203
message: option.label,
204+
trigger,
169205
},
170206
);
171207

@@ -184,9 +220,12 @@ class ChatBot extends Component {
184220
renderedSteps.pop();
185221
}
186222

187-
let nextStep = Object.assign({}, steps[currentStep.trigger]);
223+
const trigger = this.getTriggeredStep(currentStep.trigger, currentStep.value);
224+
let nextStep = Object.assign({}, steps[trigger]);
188225

189-
if (nextStep.update) {
226+
if (nextStep.message) {
227+
nextStep.message = this.getStepMessage(nextStep.message);
228+
} else if (nextStep.update) {
190229
const updateStep = nextStep;
191230
nextStep = Object.assign({}, steps[updateStep.update]);
192231

@@ -376,7 +415,7 @@ class ChatBot extends Component {
376415
}
377416

378417
renderStep(step, index) {
379-
const { renderedSteps, previousSteps } = this.state;
418+
const { renderedSteps } = this.state;
380419
const {
381420
avatarStyle,
382421
bubbleStyle,
@@ -385,19 +424,9 @@ class ChatBot extends Component {
385424
hideUserAvatar,
386425
} = this.props;
387426
const { options, component, asMessage } = step;
388-
const steps = {};
427+
const steps = this.generateRenderedStepsById();
389428
const previousStep = index > 0 ? renderedSteps[index - 1] : {};
390429

391-
for (let i = 0, len = previousSteps.length; i < len; i += 1) {
392-
const ps = previousSteps[i];
393-
394-
steps[ps.id] = {
395-
id: ps.id,
396-
message: ps.message,
397-
value: ps.value,
398-
};
399-
}
400-
401430
if (component && !asMessage) {
402431
return (
403432
<CustomStep

lib/schemas/customSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default [
3131
},
3232
{
3333
key: 'trigger',
34-
types: ['string', 'number'],
34+
types: ['string', 'number', 'function'],
3535
required: false,
3636
},
3737
{

lib/schemas/schema.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,20 @@ const schema = {
5353
const step = steps[key];
5454
const triggerId = steps[key].trigger;
5555

56-
if (step.options) {
57-
const optionsTriggerIds = step.options.map(option => option.trigger);
56+
if (typeof triggerId !== 'function') {
57+
if (step.options) {
58+
const triggers = step.options.filter(option => typeof option.trigger !== 'function');
59+
const optionsTriggerIds = triggers.map(option => option.trigger);
5860

59-
for (let i = 0, len = optionsTriggerIds.length; i < len; i += 1) {
60-
const optionTriggerId = optionsTriggerIds[i];
61-
if (optionTriggerId && !steps[optionTriggerId]) {
62-
throw new Error(`The id '${optionTriggerId}' triggered by option ${i + 1} in step '${steps[key].id}' does not exist`);
61+
for (let i = 0, len = optionsTriggerIds.length; i < len; i += 1) {
62+
const optionTriggerId = optionsTriggerIds[i];
63+
if (optionTriggerId && !steps[optionTriggerId]) {
64+
throw new Error(`The id '${optionTriggerId}' triggered by option ${i + 1} in step '${steps[key].id}' does not exist`);
65+
}
6366
}
67+
} else if (triggerId && !steps[triggerId]) {
68+
throw new Error(`The id '${triggerId}' triggered by step '${steps[key].id}' does not exist`);
6469
}
65-
} else if (triggerId && !steps[triggerId]) {
66-
throw new Error(`The id '${triggerId}' triggered by step '${steps[key].id}' does not exist`);
6770
}
6871
}
6972
},

lib/schemas/textSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default [
1616
},
1717
{
1818
key: 'trigger',
19-
types: ['string', 'number'],
19+
types: ['string', 'number', 'function'],
2020
required: false,
2121
},
2222
{

lib/schemas/updateSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default [
1111
},
1212
{
1313
key: 'trigger',
14-
types: ['string', 'number'],
14+
types: ['string', 'number', 'function'],
1515
required: true,
1616
},
1717
];

lib/schemas/userSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default [
1111
},
1212
{
1313
key: 'trigger',
14-
types: ['string', 'number'],
14+
types: ['string', 'number', 'function'],
1515
required: false,
1616
},
1717
{

lib/steps/text/TextStep.jsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,7 @@ class TextStep extends Component {
5151
});
5252
}
5353

54-
// Account for message being a callback which returns a string
55-
message = (typeof message === 'function') ?
56-
message({ previousValue, steps }) :
57-
message.replace(/{previousValue}/g, previousValue);
54+
message = message.replace(/{previousValue}/g, previousValue);
5855

5956
return message;
6057
}

lib/storage.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,41 @@ const getData = ({ cacheName, cache, firstStep, steps }, callback) => {
1212
const lastStep = data.renderedSteps[data.renderedSteps.length - 1];
1313

1414
if (lastStep && lastStep.end) {
15-
localStorage.removeItem('rsc_cache');
15+
localStorage.removeItem(cacheName);
1616
} else {
1717
for (let i = 0; i < data.renderedSteps.length; i += 1) {
18+
const renderedStep = data.renderedSteps[i];
1819
// remove delay of cached rendered steps
1920
data.renderedSteps[i].delay = 0;
2021
// flag used to avoid call triggerNextStep in cached rendered steps
2122
data.renderedSteps[i].rendered = true;
2223

2324
// an error is thrown when render a component from localStorage.
2425
// So it's necessary reassing the component
25-
if (data.renderedSteps[i].component) {
26-
const id = data.renderedSteps[i].id;
26+
if (renderedStep.component) {
27+
const id = renderedStep.id;
2728
data.renderedSteps[i].component = steps[id].component;
2829
}
2930
}
3031

32+
const { trigger, end, options } = data.currentStep;
33+
const id = data.currentStep.id;
34+
35+
if (options) {
36+
delete data.currentStep.rendered;
37+
}
38+
39+
// add trigger function to current step
40+
if (!trigger && !end) {
41+
if (options) {
42+
for (let i = 0; i < options.length; i += 1) {
43+
data.currentStep.options[i].trigger = steps[id].options[i].trigger;
44+
}
45+
} else {
46+
data.currentStep.trigger = steps[id].trigger;
47+
}
48+
}
49+
3150
// execute callback function to enable input if last step is
3251
// waiting user type
3352
if (data.currentStep.user) {

0 commit comments

Comments
 (0)