Status_API.md
1 [<https://github.com/status-im/status-react/blob/develop/resources/js/status.js#L216>](https://github.com/status-im/status-react/blob/develop/resources/js/status.js#L234) 2 3 ### status 4 5 Remember, this is all about Ethereum. Anywhere. 6 7 Below you will find the formal API specification from which you can 8 glean all the information you need to make your DApp truly mobile, with 9 native mobile commands and an intuitive chat interface through which 10 users can actually see, interact with, and pay for the services you 11 offer. 12 13 #### status.command 14 15 ##### Examples 16 17 A really simple template: 18 19 status.command({ 20 name: 'hello', 21 title: 'HelloBot', 22 description: 'Helps you say hello', 23 color: '#7099e6', 24 preview: function () { 25 return status.components.text({}, 'you’re saying hello'); 26 } 27 }); 28 29 It is important to note that params are available for any 30 `status.command()`, including in params itself. For instance, if your 31 user sends /hello whatsup, the input "whatsup" will be available in your 32 command under params.hello. You can add additional params to - for 33 instance - preview like so: 34 35 params: [{ 36 name: 'hello', 37 type: status.types.TEXT 38 placeholder: 'Why not say hello' 39 }], 40 41 The placeholder parameter above only applies if your users haven’t input 42 anything into the command, not even the name. You can use it to include 43 helpful guidance where necessary, i.e. "Type your password". 44 Alternatively, you can also include suggestions for your users’ input. 45 This should return a component to be rendered. For instance, if you are 46 using the Console DApp and you select the `/faucet` command, you’ll see 47 two suggestions to choose from. 48 49 Example validator function (this specific example will raise an error if 50 your user doesn’t input a string. Notice that you should return your 51 message inside one of the status.components): 52 53 validator: function(params) { 54 if (!params.hello) { 55 return status.components.text({}, "Say hello"); 56 } 57 } 58 59 Example of the request command to get a user send some amount of Ether 60 somewhere: 61 62 handler: function (params) { 63 return { 64 event: 'request', 65 params: [params.amount], 66 request: { 67 command: 'send', 68 params: { 69 amount: params.amount 70 } 71 } 72 }; 73 }, 74 75 Full example of pretty much all the status.command stuff in action: 76 77 status.command({ 78 name: 'faucet', 79 title: I18n.t('faucet_title'), 80 description: I18n.t('faucet_description'), 81 color: '#7099e6', 82 registeredOnly: true, 83 params: [{ 84 name: 'url', 85 type: status.types.TEXT, 86 suggestions: faucetSuggestions, 87 placeholder: I18n.t('faucet_placeholder') 88 }], 89 preview: function (params) { 90 return { 91 markup: status.components.text( 92 {}, 93 params.url 94 ) 95 }; 96 }, 97 shortPreview: function (params) { 98 return { 99 markup: status.components.text( 100 {}, 101 I18n.t('faucet_title') + ': ' + params.url 102 ) 103 }; 104 }, 105 validator: function (params, context) { 106 var f = faucets.map(function (entry) { 107 return entry.url; 108 }); 109 110 if (f.indexOf(params.url) == -1) { 111 var error = status.components.validationMessage( 112 I18n.t('faucet_incorrect_title'), 113 I18n.t('faucet_incorrect_description') 114 ); 115 116 return {markup: error}; 117 } 118 } 119 }); 120 121 ##### Parameters 122 123 | Argument | Description | 124 | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 125 | name | What your users will type in following a forward slash to invoke the command. For instance, if you wrote `name: "hello"`, your user might invoke `/hell`o. There is an additional `params` object available on any of the below commands, including in params itself. | 126 | title | This is what will appear in the list of suggestions when a user starts typing a command. | 127 | description | Appears below the `title` in the list of suggestions and allows you to provide a description of the command. | 128 | validator | Allows you to check your users’ input before sending off the command. It takes a function, which should return an error if the input is invalid. | 129 | color | Defines the background color of the name of your command as it appears in the list of suggestions. Give commands different colors to help your users distinguish commands easily, and to harmonize with your DApp’s brand and color scheme. | 130 | icon | Define which icon will appear next to action messages, such as sending Ether or requesting a location. Think an arrow for sending, a pin for location etc. | 131 | params | Defines all the possible inputs to your command. Requires an array holding an object, with possible parameters name, `placeholder`, `suggestions`, and one of the `status.types`, which are: `status.types.TEXT`, `status.types.NUMBER`, `status.types.PHONE`, and `status.types.PASSWORD`. | 132 | preview | Defines what your user will see as a result of \*their\* action, before any other response. The preview parameter takes a function, which should return a `status.component`. | 133 | shortPreview | While `preview` controls how your command appears within your DApp’s chat interface, `short-preview` controls how your commands get shown in the list of chats, before your users tap on your chat. `short-prview` expects two params: `icon` and `params`. | 134 | onSend | A self-explanatory param that takes a function which will be executed when the user presses the "send" button. It will return a map that should contain the markup value. If you specify this function, there will be no way to send a command to the chat and, in this case, the area (it’s called the `result-box`) with a specified markup will be displayed instead. | 135 | fullscreen | If your command has suggestions, this param controls whether that list of suggestions expands to fill the entire screen. See the interactive suggestion area tutorial for more. | 136 | request | This will allow you to request any action from the user, such as a phone number, password, confirmation to send Ether etc. Used with the `executeImmediately` option set to `true`, it will create a message the user can tap on an execute immediately. | 137 | executeImmediately (Boolean) | If true, this means that the `response` will be executed immediately when you press on it. For instance, when you see a response in a chat, you don’t have to type something — you just need to press on a response and it will be executed right after that. | 138 | sequentialParams (Boolean) | Specifies the way command arguments will be "requested". The default approach (`sequentialParams = false`) is to type a command this way: `/send 0.1 ETH somebody`, where `0.1`, `ETH` and `somebody` are arguments. However, there may be situations when you want to ask each argument separately. You can see the difference by executing `/password` command; it asks you for a password and, only after the user has provided one, requests confirmation. Currently there is one limitation — you can use argument types (`type` value) only for `sequentialParams`, and if you want to (for example) hide the argument input, you should use `sequentialParams` | 139 | handler (\!= null) | Of course, you probably want the command to do something when your users call it\! The `handler` parameter takes a function to accomplish this. For instance, suppose your user inputs `/hello howdy`. "Howdy" is a valid string, and will pass the `hello` validator. From there, your handler could take over to send this greeting to another user: `handler: web3.shh.post(params.hello)`. | 140 141 #### status.response 142 143 An example response for a confirmation code sent via SMS: 144 145 status.response({ 146 name: 'confirmation-code', 147 color: '#7099e6', 148 description: I18n.t('confirm_description'), 149 sequentialParams: true, 150 params: [{ 151 name: 'code', 152 type: status.types.NUMBER 153 }], 154 validator: function (params) { 155 if (!/^[\d]{4}$/.test(params.code)) { 156 var error = status.components.validationMessage( 157 I18n.t('confirm_validation_title'), 158 I18n.t('confirm_validation_description') 159 ); 160 161 return {markup: error}; 162 } 163 } 164 }); 165 166 Now that you’ve covered all the parameters for `status.command()`, you 167 can easily understand `status.response()`. This method takes the same 168 parameters that `status.command()` does. The difference is that, with 169 this method, you can actively ask a user to issue a command of their 170 own. 171 172 For example, the Status DApp Wallet allows you to `/request` money. In 173 that case, the person you’re requesting money from will see the result 174 of `status.response(send)`. In other words, they’ll be asked to give a 175 command, `/send`, in response to your `/request` command. Please check 176 line 77-158 177 [here](https://github.com/status-im/status-react/blob/30596f743f0a6ac0b7aec575cc1483dd306cc1ef/bots/wallet/bot.js#L77) 178 for more code. 179 180 The Wallet example illustrates that, as a DApp developer, you may wish 181 to use `status.command()` and `status.response()` together to create 182 dialogues of commands. You can also just use `status.response()` by 183 itself to prompt your users to enter necessary information as part of 184 the onboarding process for your DApp. 185 186 Because `status.command()` and `status.response()` take the same 187 parameters, you can sometimes use nearly the same code for both of them. 188 You simply have to consider when you want to ask a user to issue a 189 command, and when you want to just make the command available. Most of 190 the time, you’ll use `status.command()`. 191 192 #### status.on 193 194 status.on('init', function(params, context) { 195 status.sendMessage("Hello, man!"); 196 }); 197 198 This method allows your DApp to respond to events. It requires an event 199 name as a string, and a callback function. With the "init" option shown 200 here, your DApp will trigger `status.sendMessage()` when the Status app 201 loads your DApp — your DApp will greet your users even before they have 202 clicked on it. Other options include "text-change" and "message" 203 204 #### status.addListener 205 206 ##### Examples 207 208 status.addListener('on-message-input-change', 209 function (params, context) { 210 return jsSuggestions({code: params.message}, context); 211 }); 212 213 status.addListener('init', 214 function (params, context) { 215 return {'text-message': 'Hey, man!'}; 216 }); 217 218 status.addListener('on-message-send', function (params, context) { 219 if (isNaN(params.message)) { 220 return {'text-message': 'Seems that you don't want to send money :('}; 221 } 222 223 var balance = web3.eth.getBalance(context.from); 224 var value = parseFloat(params.message); 225 var weiValue = web3.toWei(value, 'ether'); 226 if (bn(weiValue).greaterThan(bn(balance))) { 227 return {'text-message': 'No way man, you don't have enough money! :)'}; 228 } 229 try { 230 web3.eth.sendTransaction({ 231 from: context.from, 232 to: context.from, 233 value: weiValue 234 }); 235 return {'text-message': 'You are the hero, you sent ' + value + ' ETH to yourself!'}; 236 } catch (err) { 237 return {'text-message': 'Something went wrong :('}; 238 } 239 }); 240 241 ##### Listeners 242 243 | Listener | Description | 244 | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 245 | on-message-input-change | This is analogous to a `text-change` event, except that it targets the chat’s input. You can find the jsSuggestions that are passed in in the example [here](https://github.com/status-im/status-react/blob/develop/resources/js/bots/console/bot.js#L316). | 246 | init | Is called once, when a new session begins ("session" is currently taken to mean the interval between login and logout from a user's account). In the example provided the bot will just send the "Hey, man\!" message to the user, but it could also it could return \`markup\` which will be shown in the suggestions area, etc. | 247 | on-message-send | Will be called when any (not command) message is sent. The example provided shows you how to send ether to yourself as a neat way of testing the functionality. | 248 249 #### status.localizeNumber 250 251 ``` 252 preview: function (params, context) { 253 return { 254 markup: status.components.text( 255 {}, 256 I18n.t('request_requesting') + ' ' 257 + status.localizeNumber(params.amount, context.delimiter, context.separator) 258 + ' ETH' 259 ) 260 }; 261 }, 262 263 ``` 264 265 A simple method to try and ensure that whatever number the user inputs, 266 is put into a usable format. The example provided shows it in use to 267 make sure the number requesting ETH is handled correctly. This is part 268 of a larger `status.command()` object that can be found 269 [here](https://github.com/status-im/status-react/blob/30596f743f0a6ac0b7aec575cc1483dd306cc1ef/bots/wallet/bot.js#L182). 270 271 #### status.types 272 273 types: { 274 TEXT: 'text', 275 NUMBER: 'number', 276 PHONE: 'phone', 277 PASSWORD: 'password' 278 } 279 280 Types dictate what sort of data your users may input. The type you 281 specify will determine what kind of keyboard gets shown to the user (if 282 you have not already defined a custom one) so that they can input their 283 response easily. It is important to specify them for a smooth, easy, and 284 intuitive UI. 285 286 ##### status.types.TEXT 287 288 status.command({ 289 name: 'faucet', 290 title: I18n.t('faucet_title'), 291 description: I18n.t('faucet_description'), 292 color: '#7099e6', 293 registeredOnly: true, 294 params: [{ 295 name: 'url', 296 type: status.types.TEXT, 297 suggestions: faucetSuggestions, 298 placeholder: I18n.t('faucet_placeholder') 299 }], 300 301 If you define a `text` input, when the user responds, it will pop up a 302 normal QWERTY keyboard. The example provided shows the first part of the 303 `status.commnad()` we use to interact with our faucet so that our users 304 can get some (test) ether to do interesting things with. 305 306 ##### status.types.NUMBER 307 308 status.response({ 309 name: 'confirmation-code', 310 color: '#7099e6', 311 description: I18n.t('confirm_description'), 312 sequentialParams: true, 313 params: [{ 314 name: 'code', 315 type: status.types.NUMBER 316 }], 317 318 Defining `number` will result in the keyboard opening to it's number 319 section. The example provided shows the first part of the 320 `status.response()` object we use to request a confirmation code from 321 the user when syncing their phone contacts. 322 323 ##### status.types.PHONE 324 325 var phoneConfig = { 326 name: 'phone', 327 registeredOnly: true, 328 icon: 'phone_white', 329 color: '#5bb2a2', 330 title: I18n.t('phone_title'), 331 description: I18n.t('phone_description'), 332 sequentialParams: true, 333 validator: function (params) { 334 return { 335 validationHandler: 'phone', 336 parameters: [params.phone] 337 }; 338 }, 339 params: [{ 340 name: 'phone', 341 type: status.types.PHONE, 342 suggestions: phoneSuggestions, 343 placeholder: I18n.t('phone_placeholder') 344 }] 345 }; 346 347 Defining `phone` will result in the keyboard opening to it's number 348 section as well. One example should suffice to give you a general idea 349 of how this works, so we have provided an excerpt of how we do phone 350 cofirmation using the `PHONE` type. You can find the full code 351 [here](https://github.com/status-im/status-react/blob/develop/resources/js/bots/console/bot.js#L456) 352 353 ##### status.types.PASSWORD 354 355 status.response({ 356 name: 'password', 357 color: '#7099e6', 358 description: I18n.t('password_description'), 359 icon: 'lock_white', 360 sequentialParams: true, 361 params: [ 362 { 363 name: 'password', 364 type: status.types.PASSWORD, 365 placeholder: I18n.t('password_placeholder'), 366 hidden: true 367 }, 368 { 369 name: 'password-confirmation', 370 type: status.types.PASSWORD, 371 placeholder: I18n.t('password_placeholder2'), 372 hidden: true 373 } 374 ] 375 }); 376 377 Defining `password` will result in the keyboard opening to it's variable 378 character section. The example provided shows the first part of the 379 `status.response()` object we use to request and confirm a password from 380 our user when they are setting up their account. 381 382 #### status.events 383 384 events: { 385 SET_VALUE: 'set-value', 386 SET_COMMAND_ARGUMENT: 'set-command-argument' 387 } 388 389 Events are essentially the glue that allow you to commuicate with the 390 Status API effectively. 391 392 ##### status.events.SET_VALUE 393 394 {onPress: status.components.dispatch([ 395 status.events.SET_VALUE, 396 entry 397 ])}, 398 399 This method will completely update the content of text input. The full 400 function around the snippet example provided can be found 401 [here](https://github.com/status-im/status-react/blob/30596f743f0a6ac0b7aec575cc1483dd306cc1ef/bots/console/bot.js#L560). 402 403 ##### status.events.SET_COMMAND_ARGUMENT 404 405 {onPress: status.components.dispatch([ 406 status.events.SET_COMMAND_ARGUMENT, 407 [0, entry.url] 408 ])}, 409 410 As opposed to `SET_VALUE`, this event will only update a single argument 411 which you define. The full function around the snippet example provided 412 can be found 413 [here](https://github.com/status-im/status-react/blob/30596f743f0a6ac0b7aec575cc1483dd306cc1ef/bots/console/bot.js#L485). 414 415 #### status.components 416 417 Create React Native Components yourself or use our pre-fabricated 418 components. 419 420 ##### status.components.view 421 422 function faucetSuggestions(params) { 423 var suggestions = faucets.map(function (entry) { 424 return status.components.touchable( 425 {onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry.url]])}, 426 status.components.view( 427 suggestionContainerStyle, 428 [status.components.view( 429 suggestionSubContainerStyle, 430 [ 431 status.components.text( 432 {style: valueStyle}, 433 entry.name 434 ), 435 status.components.text( 436 {style: descriptionStyle}, 437 entry.url 438 ) 439 ] 440 )] 441 ) 442 ); 443 }); 444 445 Standard RN component - please see 446 [JSCoach](https://js.coach/react-native) for more. 447 448 Expects 2 arguments - `options` and `element`. 449 450 The example provided shows how we use the `view` component (in 451 combination with the `text` component) to provide different suggestions 452 about which faucets our users can call to get some test ether. 453 454 ##### status.components.text 455 456 Standard RN component - please see 457 [JSCoach](https://js.coach/react-native) for more. 458 459 Expects 2 arguments - `options` and some array of strings `s`. 460 461 ##### status.components.slider 462 463 Standard RN component - please see 464 [JSCoach](https://js.coach/react-native) for more. 465 466 Expects only one argument - `options`. 467 468 Please see the `defineSubscription` method below for an example of this 469 component in action. 470 471 ##### status.components.image 472 473 Standard RN component - please see 474 [JSCoach](https://js.coach/react-native) for more. 475 476 Expects only one argument - `options`. 477 478 ##### status.components.touchable 479 480 function jsSuggestions(params, context) { 481 var suggestions = getJsSuggestions(params.code, context); 482 var sugestionsMarkup = []; 483 484 for (var i = 0; i < suggestions.length; i++) { 485 var suggestion = suggestions[i]; 486 487 if (suggestion.title.indexOf('*') >= 0) { 488 suggestion.title = createMarkupText(suggestion.title); 489 } 490 var suggestionMarkup = status.components.view(jsSuggestionContainerStyle, 491 [status.components.view(jsSubContainerStyle, 492 [ 493 status.components.text({style: jsValueStyle}, 494 suggestion.title), 495 status.components.text({style: jsDescriptionStyle}, 496 suggestion.desc) 497 ])]); 498 if (suggestion.pressValue) { 499 suggestionMarkup = status.components.touchable({ 500 onPress: status.components.dispatch([status.events.SET_VALUE, suggestion.pressValue]) 501 }, 502 suggestionMarkup 503 ); 504 } 505 sugestionsMarkup.push(suggestionMarkup); 506 } 507 508 if (sugestionsMarkup.length > 0) { 509 var view = status.components.scrollView(jsSuggestionsContainerStyle(sugestionsMarkup.length), 510 sugestionsMarkup 511 ); 512 return {markup: view}; 513 } 514 } 515 516 Standard RN component - please see 517 [JSCoach](https://js.coach/react-native) for more. 518 519 Expects 2 arguments - `options` and `element`.\] 520 521 The example provided uses the `touchable` component to make our 522 suggestions that much more native and-feeling and interactive. 523 524 It's worth noting that `touchable` components can only wrap `view` 525 components, so any touchable text for example needs to first be wrapped 526 in a `view`. 527 528 ##### status.components.scrollView 529 530 var view = status.components.scrollView( 531 suggestionsContainerStyle(ph.length), 532 suggestions 533 ); 534 535 return {markup: view}; 536 537 Standard RN component - please see 538 [JSCoach](https://js.coach/react-native) for more. 539 540 Expects 2 arguments - `options` and `elements`. 541 542 In the code snippet provided, we have taken the suggestions from the 543 example above to do `components.view` and now want to inject it into a 544 scrollView component for a better and smoother UI that our users have 545 more control over. 546 547 ##### status.components.webView 548 549 Standard RN component - please see 550 \[JSCoach\](https://js.coach/react-native) for more. Expects only 1 551 argument - \`url\` and is what we use to display - as expected - the 552 webView of a given DApp when browsing to it. 553 554 ##### status.components.validationMessage 555 556 An example of using `validationMessage` within the validator argument 557 being passed to status.command. 558 559 validator: function (params, context) { 560 var f = faucets.map(function (entry) { 561 return entry.url; 562 }); 563 564 if (f.indexOf(params.url) == -1) { 565 var error = status.components.validationMessage( 566 I18n.t('faucet_incorrect_title'), 567 I18n.t('faucet_incorrect_description') 568 ); 569 570 return {markup: error}; 571 } 572 } 573 574 This is the only custom Status component and it takes just two strings, 575 and will return them wrapped in text components inside a view. You can 576 find the full example 577 [here](https://github.com/status-im/status-react/blob/develop/resources/js/bots/console/bot.js#L566). 578 579 ##### status.components.bridgedWebview 580 581 Standard RN component - please see 582 [JSCoach](https://js.coach/react-native) for more. 583 584 Expects only 1 argument - `url`. 585 586 ##### status.components.subscribe 587 588 A method that allows you to add a subscription in the markup. 589 590 Expects only 1 argument - `path`. The added subscription will get the 591 value from the bot-db using your specified path. 592 593 ##### status.components.dispatch 594 595 var view = [ 596 'view', 597 {}, 598 ['text', {}, 'Balance ' + balance + ' ETH'], 599 ['text', {}, ['subscribe', ['doubledValue']]], 600 ['slider', { 601 maximumValue: ['subscribe', ['balance']], 602 value: defaultSliderValue, 603 minimumValue: 0, 604 onSlidingComplete: ['dispatch', ['set', 'sliderValue']], 605 step: 0.05 606 }], 607 ['touchable', 608 {onPress: ['dispatch', ['set-value-from-db', 'roundedValue']]}, 609 ['view', {}, ['text', {}, 'Set value']] 610 ], 611 ['text', {style: {color: 'red'}}, ['subscribe', ['validationText']]] 612 ]; 613 614 A method that allows you to specify an event that will be dispatched on 615 some other event that occurs inside the markup (like pressing button, 616 text change etc.). By 'markup', we mean - essentially - the view, or the 617 mobile equivalent of the DOM. 618 619 In the example provided, the variable `view` is what we mean by markup 620 (and is, in this case, part of our `superSuggestion` function found 621 [here](https://github.com/status-im/status-react/blob/2862af86c960b481ddf64ec1713e14908a366616/bots/demo_bot/bot.js#L31)) 622 we specify that `["set", "sliderValue"]` will be dispatched on 623 `onSlidingComplete`. We can’t allow user to write a real js handler 624 here, so this is our workaround for now. 625 626 #### status.setSuggestions 627 628 A method that allows you to set the suggestions that will appear in the 629 markup, whether this is something simple like sending a message, or 630 pretty much anything 631 632 #### status.setDefaultDb and status.updateDb 633 634 function superSuggestion(params, context) { 635 var balance = parseFloat(web3.fromWei(web3.eth.getBalance(context.from), 'ether')); 636 var defaultSliderValue = balance / 2; 637 638 var view = ['view', {}, 639 ['text', {}, 'Balance ' + balance + ' ETH'], 640 ['text', {}, ['subscribe', ['doubledValue']]], 641 ['slider', { 642 maximumValue: ['subscribe', ['balance']], 643 value: defaultSliderValue, 644 minimumValue: 0, 645 onSlidingComplete: ['dispatch', ['set', 'sliderValue']], 646 step: 0.05 647 }], 648 ['touchable', 649 {onPress: ['dispatch', ['set-value-from-db', 'roundedValue']]}, 650 ['view', {}, ['text', {}, 'Set value']] 651 ], 652 ['text', {style: {color: 'red'}}, ['subscribe', ['validationText']]] 653 ]; 654 655 status.setDefaultDb({ 656 sliderValue: defaultSliderValue, 657 doubledValue: doubledValueLabel({value: defaultSliderValue}) 658 }); 659 660 var validationText = '; 661 662 if (isNaN(params.message)) { 663 validationText = 'That's not a float number!'; 664 } else if (parseFloat(params.message) > balance) { 665 validationText = 666 'Input value is too big!' + 667 ' You have only ' + balance + ' ETH on your balance!'; 668 } 669 670 status.updateDb({ 671 balance: balance, 672 validationText: validationText 673 }); 674 675 return {markup: view}; 676 }; 677 678 It is easiest to show you an example of these two methods at work in our 679 \[<https://github.com/status-im/status-react/blob/2862af86c960b481ddf64ec1713e14908a366616/bots/demo_bot/bot.js#L31>) 680 demo-bot\] within a `superSuggestions` object we have created. 681 682 `status.setDefaultDb` is a method that can be used to add default values 683 to bot-db. These values will be applied to app-db only when markup is 684 rendered the first time. For instance, on each change in command input 685 suggestions handler for particular command's parameter is called, and 686 this handler returns some markup. If markup wasn't changed between calls 687 values passed to `setDefaultDb` will not be applied to bot-db 688 689 `status.updateDb` is a method that updates the bot-db, even if the 690 markup doesn't contain any changes. It too expects just 1 argument - 691 `map` 692 693 #### status.sendMessage 694 695 This has just been implemented in the latest nightlies\! Go and grab one 696 of those and you'll have access to this route, as demonstrated by our 697 updated [demo 698 bot](https://github.com/status-im/status-react/blob/master/bots/demo_bot/bot.js#L77). 699 The snippet provided also reveals how to work with the javascript 700 concept of `localStorage`. 701 702 status.addListener('on-message-send', function (params, context) { 703 var cnt = localStorage.getItem('cnt'); 704 if(!cnt) { 705 cnt = 0; 706 } 707 708 cnt++; 709 710 localStorage.setItem('cnt', cnt); 711 if (isNaN(params.message)) { 712 return {'text-message': 'Seems that you don't want to send money :(. cnt = ' + cnt}; 713 } 714 715 var balance = web3.eth.getBalance(context.from); 716 var value = parseFloat(params.message); 717 var weiValue = web3.toWei(value, 'ether'); 718 if (bn(weiValue).greaterThan(bn(balance))) { 719 return {'text-message': 'No way man, you don't have enough money! :)'}; 720 } 721 web3.eth.sendTransaction({ 722 from: context.from, 723 to: context.from, 724 value: weiValue 725 }, function (error, hash) { 726 if (error) { 727 status.sendMessage('Something went wrong, try again :('); 728 status.showSuggestions(demoSuggestions(params, context).markup); 729 } else { 730 status.sendMessage('You are the hero, you sent ' + value + ' ETH to yourself!') 731 } 732 }); 733 }); 734 735 #### status.defineSubscription 736 737 function round(n) { 738 return Math.round(n * 100) / 100; 739 } 740 741 function doubledValueLabel(params) { 742 var value = round(params.value); 743 return 'sliderValue = ' + value + '; (2 * sliderValue) = ' + (2 * value); 744 } 745 746 status.defineSubscription( 747 // the name of subscription and the name of the value in bot-db 748 // associated with this subscription 749 'doubledValue', 750 // the map of values on which subscription depends: keys are arbitrary names 751 // and values are db paths to another value 752 {value: ['sliderValue']}, 753 // the function which will be called as reaction on changes of values above, 754 // should be pure. Returned result will be associated with subscription in bot-db 755 doubledValueLabel 756 ); 757 758 status.defineSubscription( 759 'roundedValue', 760 {value: ['sliderValue']}, 761 function (params) { 762 return round(params.value); 763 } 764 ); 765 766 This method was added to allow a bot to react on changes in the bot-db 767 and add another calculated value to that bot-db in the result. 768 769 It expects 3 arguments: the name of subscription, a map of values on 770 which the subscription depends, and a callback function.