Skip to content

Commit

Permalink
add function option to trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasBassetti committed Aug 24, 2017
1 parent a8fdba1 commit 4dcd603
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 42 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
localStorage: true,
},
"rules": {
"guard-for-in": ["off"],
"no-console": ["off"],
"no-use-before-define": ["off"],
"no-restricted-syntax": ["off"],
Expand Down
2 changes: 1 addition & 1 deletion dist/react-simple-chatbot.js

Large diffs are not rendered by default.

63 changes: 46 additions & 17 deletions lib/ChatBot.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class ChatBot extends Component {
};

this.renderStep = this.renderStep.bind(this);
this.getTriggeredStep = this.getTriggeredStep.bind(this);
this.generateRenderedStepsById = this.generateRenderedStepsById.bind(this);
this.triggerNextStep = this.triggerNextStep.bind(this);
this.onValueChange = this.onValueChange.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
Expand Down Expand Up @@ -82,6 +84,14 @@ class ChatBot extends Component {

schema.checkInvalidIds(steps);

const firstStep = this.props.steps[0];

if (firstStep.message) {
const message = firstStep.message;
firstStep.message = typeof message === 'function' ? message() : message;
steps[firstStep.id].message = firstStep.message;
}

const {
currentStep,
previousStep,
Expand All @@ -90,7 +100,7 @@ class ChatBot extends Component {
} = storage.getData({
cacheName,
cache,
firstStep: this.props.steps[0],
firstStep,
steps,
}, () => {
// focus input if last step cached is a user step
Expand Down Expand Up @@ -133,6 +143,31 @@ class ChatBot extends Component {
this.setState({ inputValue: event.target.value });
}

getTriggeredStep(trigger, value) {
const steps = this.generateRenderedStepsById();
return (typeof trigger === 'function') ? trigger({ value, steps }) : trigger;
}

getStepMessage(message) {
const { previousSteps } = this.state;
const lastStepIndex = previousSteps.length > 0 ? previousSteps.length - 1 : 0;
const steps = this.generateRenderedStepsById();
const previousValue = previousSteps[lastStepIndex].value;
return (typeof message === 'function') ? message({ previousValue, steps }) : message;
}

generateRenderedStepsById() {
const { previousSteps } = this.state;
const steps = {};

for (let i = 0, len = previousSteps.length; i < len; i += 1) {
const { id, message, value } = previousSteps[i];
steps[id] = { id, message, value };
}

return steps;
}

triggerNextStep(data) {
const {
defaultUserSettings,
Expand All @@ -147,13 +182,14 @@ class ChatBot extends Component {
currentStep.value = data.value;
}
if (data && data.trigger) {
currentStep.trigger = data.trigger;
currentStep.trigger = this.getTriggeredStep(data.trigger, data.value);
}

if (isEnd) {
this.handleEnd();
} else if (currentStep.options && data) {
const option = currentStep.options.filter(o => o.value === data.value)[0];
const trigger = this.getTriggeredStep(option.trigger, currentStep.value);
delete currentStep.options;

// replace choose option for user message
Expand All @@ -164,8 +200,8 @@ class ChatBot extends Component {
defaultUserSettings,
{
user: true,
trigger: option.trigger,
message: option.label,
trigger,
},
);

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

let nextStep = Object.assign({}, steps[currentStep.trigger]);
const trigger = this.getTriggeredStep(currentStep.trigger, currentStep.value);
let nextStep = Object.assign({}, steps[trigger]);

if (nextStep.update) {
if (nextStep.message) {
nextStep.message = this.getStepMessage(nextStep.message);
} else if (nextStep.update) {
const updateStep = nextStep;
nextStep = Object.assign({}, steps[updateStep.update]);

Expand Down Expand Up @@ -376,7 +415,7 @@ class ChatBot extends Component {
}

renderStep(step, index) {
const { renderedSteps, previousSteps } = this.state;
const { renderedSteps } = this.state;
const {
avatarStyle,
bubbleStyle,
Expand All @@ -385,19 +424,9 @@ class ChatBot extends Component {
hideUserAvatar,
} = this.props;
const { options, component, asMessage } = step;
const steps = {};
const steps = this.generateRenderedStepsById();
const previousStep = index > 0 ? renderedSteps[index - 1] : {};

for (let i = 0, len = previousSteps.length; i < len; i += 1) {
const ps = previousSteps[i];

steps[ps.id] = {
id: ps.id,
message: ps.message,
value: ps.value,
};
}

if (component && !asMessage) {
return (
<CustomStep
Expand Down
2 changes: 1 addition & 1 deletion lib/schemas/customSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default [
},
{
key: 'trigger',
types: ['string', 'number'],
types: ['string', 'number', 'function'],
required: false,
},
{
Expand Down
19 changes: 11 additions & 8 deletions lib/schemas/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,20 @@ const schema = {
const step = steps[key];
const triggerId = steps[key].trigger;

if (step.options) {
const optionsTriggerIds = step.options.map(option => option.trigger);
if (typeof triggerId !== 'function') {
if (step.options) {
const triggers = step.options.filter(option => typeof option.trigger !== 'function');
const optionsTriggerIds = triggers.map(option => option.trigger);

for (let i = 0, len = optionsTriggerIds.length; i < len; i += 1) {
const optionTriggerId = optionsTriggerIds[i];
if (optionTriggerId && !steps[optionTriggerId]) {
throw new Error(`The id '${optionTriggerId}' triggered by option ${i + 1} in step '${steps[key].id}' does not exist`);
for (let i = 0, len = optionsTriggerIds.length; i < len; i += 1) {
const optionTriggerId = optionsTriggerIds[i];
if (optionTriggerId && !steps[optionTriggerId]) {
throw new Error(`The id '${optionTriggerId}' triggered by option ${i + 1} in step '${steps[key].id}' does not exist`);
}
}
} else if (triggerId && !steps[triggerId]) {
throw new Error(`The id '${triggerId}' triggered by step '${steps[key].id}' does not exist`);
}
} else if (triggerId && !steps[triggerId]) {
throw new Error(`The id '${triggerId}' triggered by step '${steps[key].id}' does not exist`);
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion lib/schemas/textSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default [
},
{
key: 'trigger',
types: ['string', 'number'],
types: ['string', 'number', 'function'],
required: false,
},
{
Expand Down
2 changes: 1 addition & 1 deletion lib/schemas/updateSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default [
},
{
key: 'trigger',
types: ['string', 'number'],
types: ['string', 'number', 'function'],
required: true,
},
];
2 changes: 1 addition & 1 deletion lib/schemas/userSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default [
},
{
key: 'trigger',
types: ['string', 'number'],
types: ['string', 'number', 'function'],
required: false,
},
{
Expand Down
5 changes: 1 addition & 4 deletions lib/steps/text/TextStep.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ class TextStep extends Component {
});
}

// Account for message being a callback which returns a string
message = (typeof message === 'function') ?
message({ previousValue, steps }) :
message.replace(/{previousValue}/g, previousValue);
message = message.replace(/{previousValue}/g, previousValue);

return message;
}
Expand Down
25 changes: 22 additions & 3 deletions lib/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,41 @@ const getData = ({ cacheName, cache, firstStep, steps }, callback) => {
const lastStep = data.renderedSteps[data.renderedSteps.length - 1];

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

// an error is thrown when render a component from localStorage.
// So it's necessary reassing the component
if (data.renderedSteps[i].component) {
const id = data.renderedSteps[i].id;
if (renderedStep.component) {
const id = renderedStep.id;
data.renderedSteps[i].component = steps[id].component;
}
}

const { trigger, end, options } = data.currentStep;
const id = data.currentStep.id;

if (options) {
delete data.currentStep.rendered;
}

// add trigger function to current step
if (!trigger && !end) {
if (options) {
for (let i = 0; i < options.length; i += 1) {
data.currentStep.options[i].trigger = steps[id].options[i].trigger;
}
} else {
data.currentStep.trigger = steps[id].trigger;
}
}

// execute callback function to enable input if last step is
// waiting user type
if (data.currentStep.user) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-simple-chatbot",
"version": "0.2.5",
"version": "0.2.6",
"description": "React Simple Chatbot",
"main": "dist/react-simple-chatbot.js",
"scripts": {
Expand Down
6 changes: 3 additions & 3 deletions tests/lib/ChatBot.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('ChatBot', () => {
{
id: 'update',
update: 'user',
trigger: '2',
trigger: () => '2',
},
{
id: '2',
Expand All @@ -59,7 +59,7 @@ describe('ChatBot', () => {
{
id: '5',
options: [
{ value: 'op1', label: 'Option 1', trigger: '6' },
{ value: 'op1', label: 'Option 1', trigger: () => '6' },
{ value: 'op2', label: 'Option 2', trigger: '6' },
],
},
Expand Down Expand Up @@ -180,7 +180,7 @@ describe('ChatBot', () => {
},
{
id: '2',
message: 'Bye',
message: () => 'Bye',
end: true,
},
]}
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/TextStep.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ describe('TextStep', () => {
const settings = {
step: {
id: '1',
message: () => 'Hello',
message: 'Hello',
delay: 1000,
user: true,
bubbleColor: '#eee',
Expand Down

0 comments on commit 4dcd603

Please sign in to comment.