Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2597 Add tableflip script #2598

Merged
merged 2 commits into from
Nov 14, 2019
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
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

### Breaking changes

- `adaptiveCardHostConfig` is being renamed to `adaptiveCardsHostConfig`
- If you are using the deprecated `adaptiveCardHostConfig`, we will rename it automatically
- `adaptiveCardHostConfig` is being renamed to `adaptiveCardsHostConfig`
- If you are using the deprecated `adaptiveCardHostConfig`, we will rename it automatically

### Fixed

Expand All @@ -41,8 +41,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- PR [#2541](https://github.com/microsoft/BotFramework-WebChat/pull/2541): `useStyleOptions`, `useStyleSet`
- PR [#2542](https://github.com/microsoft/BotFramework-WebChat/pull/2542): `useLanguage`, `useLocalize`, `useLocalizeDate`
- PR [#2543](https://github.com/microsoft/BotFramework-WebChat/pull/2543): `useAdaptiveCardsHostConfig`, `useAdaptiveCardsPackage`, `useRenderMarkdownAsHTML`
- Bring your own Adaptive Cards package by specifying `adaptiveCardsPackage` prop, by [@compulim](https://github.com/compulim) in PR [#2543](https://github.com/microsoft/BotFramework-WebChat/pull/2543)
- Bring your own Adaptive Cards package by specifying `adaptiveCardsPackage` prop, by [@compulim](https://github.com/compulim) in PR [#2543](https://github.com/microsoft/BotFramework-WebChat/pull/2543)
- PR [#2544](https://github.com/microsoft/BotFramework-WebChat/pull/2544): `useAvatarForBot`, `useAvatarForUser`
- Fixes [#2597](https://github.com/microsoft/BotFramework-WebChat/issues/2597). Modify `watch` script to `start` and add `tableflip` script for throwing `node_modules`, by [@corinagum](https://github.com/corinagum) in PR [#2598](https://github.com/microsoft/BotFramework-WebChat/pull/2598)

### Fixed

Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,14 @@
"lerna-publish": "lerna publish",
"prepublishOnly": "lerna run --scope=botframework-webchat* --scope=isomorphic* --scope=playground --stream prepublishOnly",
"prettier-readmes": "prettier --write **/**/*.md --tab-width 3 --single-quote true",
"start": "npm run build && lerna run --parallel --scope=botframework-webchat* --scope=isomorphic* --stream watch",
"start:docker": "npm run build && docker-compose up --build",
"start:playground": "cd packages/playground && npm run start",
"tableflip": "npm run tableflip:start && lerna clean --yes --concurrency 2 && npx rimraf node_modules && npm ci && npm run bootstrap -- --concurrency 2 && npm run tableflip:end",
"tableflip:end": "echo ┬──┬ ノ( ゜-゜ノ) Tableflip complete. Now run npm start",
"tableflip:start": "echo (╯ರ ~ ರ)╯︵ ┻━┻ Begin tableflip.",
"test": "jest --no-cache",
"test:all": "lerna run --parallel --stream test",
"watch": "lerna run --parallel --scope=botframework-webchat* --scope=isomorphic* --stream watch"
"test:all": "lerna run --parallel --stream test"
},
"devDependencies": {
"@azure/storage-blob": "^12.0.0",
Expand Down
183 changes: 91 additions & 92 deletions samples/17.b.clear-after-idle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,90 +27,88 @@ This sample shows how to replace Web Chat's store to clear the conversation.

## Overview


This sample demonstrates how to clear the conversation data and start a new conversation with the user after the conversation has sat idle for a set time. To accomplish this, we created a custom hook - `useTimer` - that takes a callback as a parameter, which is called when the timer expires, and returns an array containing the time remaining in milliseconds - `timeRemaining` - and a method to set the time remaining - `setTimeRemaining`.
This sample demonstrates how to clear the conversation data and start a new conversation with the user after the conversation has sat idle for a set time. To accomplish this, we created a custom hook - `useTimer` - that takes a callback as a parameter, which is called when the timer expires, and returns an array containing the time remaining in milliseconds - `timeRemaining` - and a method to set the time remaining - `setTimeRemaining`.

```javascript
import { useEffect, useState } from 'react';

export default function useTimer(fn, step = 1000) {
const [timeRemaining, setTimeRemaining] = useState();

useEffect(() => {
let timeout;
if (timeRemaining > 0) {
timeout = setTimeout(() => setTimeRemaining(ms => (ms > step ? ms - step : 0)), step);
} else if (timeRemaining === 0) {
setTimeRemaining();
fn();
}
const [timeRemaining, setTimeRemaining] = useState();

useEffect(() => {
let timeout;
if (timeRemaining > 0) {
timeout = setTimeout(() => setTimeRemaining(ms => (ms > step ? ms - step : 0)), step);
} else if (timeRemaining === 0) {
setTimeRemaining();
fn();
}

return () => clearTimeout(timeout);
}, [fn, timeRemaining, setTimeRemaining, step]);
return () => clearTimeout(timeout);
}, [fn, timeRemaining, setTimeRemaining, step]);

return [timeRemaining, setTimeRemaining];
return [timeRemaining, setTimeRemaining];
}

```

We also created a custom store middleware that resets the timer by calling `setTimeRemaining` with the default time interval when the user submits the send box.

```javascript
setStore(createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
} else if (action.type === 'WEB_CHAT/SUBMIT_SEND_BOX') {
// Reset the timer when the user sends an activity
setTimeRemaining(TIME_INTERVAL);
}

return next(action);
}));
```

If the user stops participating in the conversation and the timer expires, we will replace the store to clear the conversation data. However, when the store is replaced, Web Chat dispatches a `'DIRECT_LINE/DISCONNECT'`, so we also need to request a new token. The `initConversation` method handles both replacing the custom store and requesting a new Direct Line token to start a new conversation with the bot. This function is passed to the `useTimer` hook so the conversation will be restarted when the timer expires.

```javascript
const initConversation = useCallback(() => {
setStore(
createStore({}, ({ dispatch }) => next => action => {
setStore(
createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
} else if (action.type === 'WEB_CHAT/SUBMIT_SEND_BOX') {
// Reset the timer when the user sends an activity
setTimeRemaining(TIME_INTERVAL);
// Reset the timer when the user sends an activity
setTimeRemaining(TIME_INTERVAL);
}

return next(action);
})
);
})
);
```

(async function() {
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
If the user stops participating in the conversation and the timer expires, we will replace the store to clear the conversation data. However, when the store is replaced, Web Chat dispatches a `'DIRECT_LINE/DISCONNECT'`, so we also need to request a new token. The `initConversation` method handles both replacing the custom store and requesting a new Direct Line token to start a new conversation with the bot. This function is passed to the `useTimer` hook so the conversation will be restarted when the timer expires.

setDirectLine(createDirectLine({ token }));
})().catch(error => console.log(error));
```javascript
const initConversation = useCallback(() => {
setStore(
createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
} else if (action.type === 'WEB_CHAT/SUBMIT_SEND_BOX') {
// Reset the timer when the user sends an activity
setTimeRemaining(TIME_INTERVAL);
}

return next(action);
})
);

(async function() {
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();

setDirectLine(createDirectLine({ token }));
})().catch(error => console.log(error));
}, [setStore, setDirectLine]);

useEffect(initConversation, []);

const [timeRemaining, setTimeRemaining] = useTimer(initConversation);
```
```

## Completed Code

Expand All @@ -127,46 +125,46 @@ import useTimer from './utils/useTimer';
const TIME_INTERVAL = 30000;

function App() {
const [directLine, setDirectLine] = useState(createDirectLine({}));
const [store, setStore] = useState();

const initConversation = useCallback(() => {
setStore(createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
const [directLine, setDirectLine] = useState(createDirectLine({}));
const [store, setStore] = useState();

const initConversation = useCallback(() => {
setStore(
createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
} else if (action.type === 'WEB_CHAT/SUBMIT_SEND_BOX') {
setTimeRemaining(TIME_INTERVAL);
}
});
} else if (action.type === 'WEB_CHAT/SUBMIT_SEND_BOX') {
setTimeRemaining(TIME_INTERVAL);
}

return next(action);
}));
return next(action);
})
);

(async function() {
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
(async function() {
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();

setDirectLine(createDirectLine({ token }));
})().catch(error => console.log(error));
}, [setStore, setDirectLine]);
setDirectLine(createDirectLine({ token }));
})().catch(error => console.log(error));
}, [setStore, setDirectLine]);

useEffect(initConversation, []);
useEffect(initConversation, []);

const [timeRemaining, setTimeRemaining] = useTimer(initConversation);
const [timeRemaining, setTimeRemaining] = useTimer(initConversation);

return (
<div className="App">
<Timer timeRemaining={timeRemaining} />
<ReactWebChat className="chat" directLine={directLine} store={store} />
</div>
);
return (
<div className="App">
<Timer timeRemaining={timeRemaining} />
<ReactWebChat className="chat" directLine={directLine} store={store} />
</div>
);
}

export default App;
Expand All @@ -176,6 +174,7 @@ export default App;

- [Hooks at a Glance](https://reactjs.org/docs/hooks-overview.html)
- [Web Chat Back Channel Welcome Event Sample](https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/15.d.backchannel-send-welcome-event)

## Full list of Web Chat hosted samples

View the list of [available Web Chat samples](https://github.com/microsoft/BotFramework-WebChat/tree/master/samples)