Skip to content

Commit

Permalink
Feature/conversations (#480)
Browse files Browse the repository at this point in the history
* VIDEO 3731 Conversations UI - create chat window (#421)

* Video 4078 add flip camera button to mobile menu (#433)

VIDEO 4078 Conversations - Add flip camera button to 'more' mobile menu

* Video 3730 add conversation hooks (#438)

* Add initial hooks for chat

* Update hooks in chat provider

* Add tests for conversationProvider component

* Fix DeviceSelectionScreen tests

* Update variable names

* Revert proxy url in package.json

* Fix linting issues

* Make error handling more user friendly

* Fix a test in src/state

* Temporarily disable cypress tests

* Undo prettier changes to config.yml

* Update chatProvider test

* Cleanup ChatProvider

* Video 3732 Conversations UI - create message components (#441)

* Add links to TextMessage component (#446)

* Add links to TextMessage component

* Update CSS in TextMessage

* Update snapshot test

* Fix issue in addLinks function

* Use forEach loop in addLinks function

* Add new server (#443)

* Use new server with reused code

* Add firebase auth to server

* Convert server to typescript

* Add tests for firebaseAuthMiddleware

* Refactor server

* Add more server tests

* Add tests for CreateExpressHandler

* Fix linter issue

* Delete old server

* Fix linter issues

* Fix some server issues

* Set up server build steps

* Change request to match new server api

* Fix token fetch test

* Add server build step to circleci config

* Enable cyress tests in CI

* Undo prettier changes in config.yml

* install plugin-rtc from npm

* Fix firebaseAuth test

* Add create_conversation:true to token requests

* Upgrade plugin-rtc to 0.8.0

* Temorarily remove firebaseAuthMiddleware and recording rules route

* Add ChatProvider back in

* Update .env.example

* Change build:server script

* Add firebaseAuthMiddleware

* Add comments to firebaseAuthMiddleware

* Update useFirebaseAuth tests

* Video 3728 Conversations UI - add input field and send button (#451)

* Chat notification (#454)

* Add notification to chat icon

* Add tests for ToggleChatButton

* Some cleanup

* Fix linting issue

* Video-4525 loading screen (#461)

* Video 4454 Conversations UI -  message list scrolling (#467)

* Update MessageList component to change how messages are grouped (#469)

* Update MessageList component to change how messages are grouped

* Simplify MessageList code

* Video 3888 file input for conversations (#458)

* Add FileAttachmentIcon

* Add File Input to ChatInput component

* Add change handler to file input

* Create MediaMessage component and add it to MessageList

* Toggle ChatWindow visibility with CSS

* Update messageList tests

* Add function to format the file size

* Update error handling in ChatInput component

* Add tests for MediaMessage component

* Update snapshot test

* Add tests for ChatInput

* Fix linting issue

* Update filesize formatting

* Update error language and tests

* Reset file input value after file sent

* Center icon in MediaMessage

* Update Icon size

* Fix breaking ChatInput test

* Update snapshot

* Use accept attribute on file input element

* Update readme to add information about the chat feature and conversations api

* Cross browser fixes (#472)

* Update app.yaml for the new server

* Add cache controls for static assets

* Only hide Screenshare button on mobile devices

* Auto focus on chat input when user opens chat window

* Fix iOS bug with media messages

* Fix issues in MessageListScrollContainer

* Fix app.yaml

* Fix infinite loop when there is a conversations error

* Update tests for ChatInput

* Update mediamessage test

* Update menubar tests

* Update messageList snapshot

* Fix linting issue

* Add comments to the server

* Video 3727 - cypress testing (#473)

* Video 4597 feature flag (#475)

* Update plugin-rtc version

* Add feature flag for Twilio Conversations

* Add tests

* Add info to .env.example

* Update readme with info about twilio conversations (#476)

* Update readme with info about twilio conversations

* Update readme to address feedback

* Release 0.3.0 (#479)

* Bump version and update changelog

* Add plugin-rtc upgrade instructions to the readme

Co-authored-by: olipyskoty <77076398+olipyskoty@users.noreply.github.com>
Co-authored-by: Sean Coleman <smcoleman27@gmail.com>
  • Loading branch information
3 people authored Mar 31, 2021
1 parent ca57323 commit b12ba32
Show file tree
Hide file tree
Showing 75 changed files with 6,105 additions and 493 deletions.
38 changes: 21 additions & 17 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- v1-deps-{{ .Branch }}-{{ checksum "package-lock.json" }}
- v1-deps-{{ .Branch }}
- v1-deps

- run: npm ci

- save_cache:
Expand All @@ -24,29 +24,33 @@ jobs:
- ~/.cache

- run:
name: "Jest Unit Tests"
name: 'Jest Unit Tests'
command: npm run test:ci
environment:
JEST_JUNIT_OUTPUT_DIR: "test-reports/jest"
JEST_JUNIT_OUTPUT_NAME: "results.xml"
JEST_JUNIT_CLASSNAME: "{classname}"
JEST_JUNIT_TITLE: "{title}"
JEST_JUNIT_OUTPUT_DIR: 'test-reports/jest'
JEST_JUNIT_OUTPUT_NAME: 'results.xml'
JEST_JUNIT_CLASSNAME: '{classname}'
JEST_JUNIT_TITLE: '{title}'

- store_artifacts:
path: coverage

- run:
name: "Eslint"
- run:
name: 'Eslint'
command: npm run lint -- --max-warnings 0

- run:
name: "Build app with Firebase auth disabled"
- run:
name: 'Check server types'
command: npm run typescript:server

- run:
name: 'Build app with Firebase auth disabled'
command: npm run build
environment:
REACT_APP_TOKEN_ENDPOINT: "http://localhost:8081/token"
REACT_APP_TOKEN_ENDPOINT: 'http://localhost:8081/token'

- run:
name: "Set environment variables for local token server (used by Cypress tests)"
- run:
name: 'Set environment variables for local token server (used by Cypress tests)'
command: |
echo TWILIO_ACCOUNT_SID=$TWILIO_ACCOUNT_SID >> .env
echo TWILIO_API_KEY_SID=$TWILIO_API_KEY >> .env
Expand All @@ -59,7 +63,7 @@ jobs:

# Rebuild app with firebase auth enabled
- run:
name: "Build app with Firebase auth enabled"
name: 'Build app with Firebase auth enabled'
command: |
echo REACT_APP_SET_AUTH=firebase >> .env
echo REACT_APP_TOKEN_ENDPOINT=$REACT_APP_TOKEN_ENDPOINT >> .env
Expand All @@ -74,7 +78,7 @@ jobs:
- persist_to_workspace:
root: .
paths:
paths:
- .

deploy:
Expand All @@ -85,7 +89,7 @@ jobs:
steps:
- attach_workspace:
at: ~/twilio-video-react-app

- run: |
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
Expand All @@ -109,4 +113,4 @@ workflows:
tags:
only: /^v.*/
branches:
ignore: /.*/
ignore: /.*/
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ TWILIO_ACCOUNT_SID=AC00000000000000000000000000000000
TWILIO_API_KEY_SID=SK00000000000000000000000000000000
TWILIO_API_KEY_SECRET=00000000000000000000000000000000

# TWILIO_CONVERSATIONS_SERVICE_SID must be populated in order to use the chat feature in the app.
# Note: this variable is not required if REACT_APP_DISABLE_TWILIO_CONVERSATIONS is set to 'true'.
TWILIO_CONVERSATIONS_SERVICE_SID=IS00000000000000000000000000000000

# Un-comment the following line to disable the Twilio Conversations functionality in the app.
# REACT_APP_DISABLE_TWILIO_CONVERSATIONS=true

# Un-comment the following line to use a custom endpoint for obtaining tokens. Defaults to /token
# REACT_APP_TOKEN_ENDPOINT=https://example.com/token

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ yarn-error.log*

test-reports
junit.xml
serviceAccountKey.json
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.3.0

### New Feature

- This release adds an in-room chat feature. This chat feature allows users to send and receive textual messages and files while connected to a Twilio Video room. This feature is powered by the [Twilio Conversations API](https://www.twilio.com/conversations-api). For more information, please see this [blog post](https://www.twilio.com/blog/open-source-video-chat-app-reactjs-conversations-api).

## 0.2.4

### Bugfixes
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2020 Twilio Inc.
Copyright 2021 Twilio Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
81 changes: 44 additions & 37 deletions README.md

Large diffs are not rendered by default.

29 changes: 9 additions & 20 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
runtime: python27
api_version: 1
threadsafe: true
runtime: nodejs12

handlers:
- url: /static
secure: always
static_dir: build/static

- url: /(.*\.(json|ico|js|txt|png))$
secure: always
static_files: build/\1
upload: build/.*\.(json|ico|js|txt|png)$
entrypoint: npm run server

- url: /.well-known/apple-app-site-association
secure: always
static_files: build/.well-known/apple-app-site-association
upload: build/.well-known/apple-app-site-association
env_variables:
REACT_APP_SET_AUTH: 'firebase'

- url: .*
secure: always
static_files: build/index.html
upload: build/index.html
handlers:
- url: /.*
secure: always
redirect_http_response_code: 301
script: auto
70 changes: 70 additions & 0 deletions cypress/integration/twilio-video.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,76 @@ context('A video app user', () => {
it('should be able to hear the other participant', () => {
cy.getParticipant('test1').shouldBeMakingSound();
});

describe('the chat feature', () => {
// Before we test the chat feature, we want to open the chat window and send enough messages
// to make the message list taller than its container so that we can test the scrolling behavior:
before(() => {
cy.get('[data-cy-chat-button]').click();
// Create an array with 15 values, then send a message when looping over each of them:
Array(15)
.fill(true)
.forEach((_, i) => {
cy.task('sendAMessage', {
name: 'test1',
message: 'welcome to the chat! - ' + i,
});
});
// Wait 1 second for the above to complete:
cy.wait(1000);
cy.contains('welcome to the chat! - 14');
});

after(() => {
cy.get('[data-cy-chat-button]').click();
});

it('should see "1 new message" button when not scrolled to bottom of chat and a new message is received', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'how is it going?' });
cy.contains('1 new message').should('be.visible');
});

it('should scroll to bottom of chat when "1 new message button" is clicked on', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'Ahoy!' });
cy.contains('Ahoy!');
cy.get('[data-cy-new-message-button]')
.should('be.visible')
.click();
cy.get('[data-cy-message-list-inner-scroll]')
.contains('Ahoy!')
.should('be.visible');

// Here we are checking if the chat window has scrolled all the way to the bottom.
// The following will be true if the scrolling container's scrollHeight property
// is equal to its 'scrollTop' plus its 'clientHeight' properties:
cy.get('[data-cy-message-list-inner-scroll]').should($el => {
expect($el.prop('scrollHeight')).to.equal($el.prop('scrollTop') + $el.prop('clientHeight'));
});
});

it('should not see "1 new message" button when manually scroll to bottom of chat after receiving new message', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo(0, 0);
cy.task('sendAMessage', { name: 'test1', message: 'chatting is fun!' });
cy.get('[data-cy-new-message-button]').should('be.visible');
cy.get('[data-cy-message-list-inner-scroll]').scrollTo('bottom');
cy.get('[data-cy-new-message-button]').should('not.be.visible');
cy.get('[data-cy-message-list-inner-scroll]')
.contains('chatting is fun!')
.should('be.visible');
});

it('should auto-scroll to bottom of chat when already scrolled to bottom and a new message is received', () => {
cy.get('[data-cy-message-list-inner-scroll]').scrollTo('bottom');
cy.task('sendAMessage', { name: 'test1', message: 'what a wonderful day!' });
cy.contains('what a wonderful day!');
// Check if chat window is scrolled to the bottom:
cy.get('[data-cy-message-list-inner-scroll]').should($el => {
expect($el.prop('scrollHeight')).to.equal($el.prop('scrollTop') + $el.prop('clientHeight'));
});
});
});
});

describe('when entering an empty room that three participants will join', () => {
Expand Down
7 changes: 7 additions & 0 deletions cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ module.exports = (on, config) => {
delete participants[name];
return Promise.resolve(null);
},
sendAMessage: async ({ message, name }) => {
const page = participants[name];
await page.click('[data-cy-chat-button]');
await page.type('[data-cy-chat-input]', message);
await page.click('[data-cy-send-message-button]');
return Promise.resolve(null);
},
};
on('task', participantFunctions);
};
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
roots: ['<rootDir>/src'],
roots: ['<rootDir>/src', '<rootDir>/server'],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
Expand Down
Loading

0 comments on commit b12ba32

Please sign in to comment.