├── src ├── favicon.ico ├── img │ ├── Verto-logo.png │ └── FreeSwitch-Logo.png ├── js │ ├── whitelabel.js │ ├── whitelabelData.js │ ├── contributorService.js │ ├── messages.js │ ├── callHistoryService.js │ └── alertService.js ├── containers │ ├── reducers.js │ ├── appbar │ │ └── action-creators.js │ └── main │ │ └── auth-reducers.js ├── css │ └── main.css ├── tests │ ├── browser-test.js │ ├── lastcall-test.js │ ├── vcstatus-test.js │ ├── login-test.js │ ├── splashmessage-test.js │ ├── alertList-test.js │ ├── chatinput-test.js │ ├── userMenu-test.js │ ├── input-test.js │ ├── chatmessageitem-test.js │ ├── contributors-test.js │ ├── numberitem-test.js │ ├── chatmessagelist-test.js │ ├── splash-test.js │ ├── settingspreview-test.js │ ├── numberpad-test.js │ ├── settingsMenuSelect-test.js │ ├── alertLog-test.js │ ├── contributorlistitem-test.js │ ├── aboutComp-test.js │ ├── nsindicator-test.js │ ├── volumemeter-test.js │ ├── membersadmincontrols-test.js │ ├── browserInfo-test.js │ ├── dialpad-test.js │ ├── controlItem-test.js │ ├── memberList-test.js │ └── specs │ │ └── index.js ├── components │ ├── badge.js │ ├── menuItem.js │ ├── tooltip.js │ ├── app.js │ ├── browser.js │ ├── list-select.js │ ├── contributorsListItem.js │ ├── controlItem.js │ ├── volumeMeter.js │ ├── lastCall.js │ ├── vertobasecomponent.js │ ├── alertList.js │ ├── about.js │ ├── contributors.js │ ├── numberitem.js │ ├── chatMessageList.js │ ├── splashmessage.js │ ├── chatInput.js │ ├── splash.js │ ├── vcstatus.js │ ├── memberList.js │ ├── chatSession.js │ ├── tabbedContainer.js │ ├── settingsMenuSelect.js │ ├── alertItem.js │ ├── inputModal.js │ └── alertLogItem.js ├── helpers │ └── intl-enzyme-test-helper.js ├── 3rd-party │ ├── jquery.cookie.1.4.1.min.js │ └── jquery.json.2.5.1.min.js ├── config │ └── contributorsData.js └── index.html ├── .gitignore ├── documents ├── img │ ├── chi.png │ ├── input.png │ ├── login.png │ ├── dialpad.png │ ├── nsi-icon.png │ ├── nsi-menu.png │ ├── preview.png │ ├── um-icon.png │ ├── um-menu.png │ ├── Status-Icon.png │ ├── about-img.png │ ├── admin-img 2.png │ ├── admin-img.png │ ├── alertItem.png │ ├── alertList.png │ ├── callhistory.png │ ├── chaltstate.png │ ├── numberpad.png │ ├── alertLog-full.png │ ├── alertLogItem.png │ ├── chatinput-img.png │ ├── contributors.png │ ├── progress-img.png │ ├── verto-appbar.png │ ├── volume-meter.png │ ├── Template-Image.png │ ├── alertLog-noData.png │ ├── contributors-img.png │ ├── lastcall-example.png │ ├── memberItem-img.png │ ├── memberList-img.png │ ├── preview-settings.png │ ├── splash-screenshot.png │ ├── Settings-image-full.png │ ├── chatmessageitem-img.png │ ├── chatmessagelist-img.png │ ├── settings-cbox-checked.png │ ├── vcstatus-conencting.png │ ├── vcstatus-disconnected.png │ ├── floor-presenter-badges.png │ ├── settings-cbox-unchecked.png │ ├── settings-preview-modal.png │ ├── settings-menuSelect-open.png │ ├── splashmessage-screenshot.png │ ├── floorlocked-presenter-badges.png │ ├── settings-menuSelect-default.png │ └── settings-video-secondary-menu.png ├── volumeMeter-spec.md ├── contributors-spec.md ├── about-spec.md ├── chatmessageitem-spec.md ├── browser-info-spec.md ├── memberList-spec.md ├── chatmessagelist-spec.md ├── contributorslistitem-spec.md ├── alertList-spec.md ├── splash-spec.md ├── memberadmincontrols-spec.md ├── login-spec.md ├── numberpad-spec.md ├── splashmessage-spec.md ├── appbar-spec.md ├── lastcall-spec.md ├── vcstatus-spec.md ├── input-spec.md ├── callhistoryitem-spec.md ├── userMenu-spec.md ├── checkbox-spec.md ├── alertLog-spec.md ├── chatinput-spec.md ├── settings-preview-spec.md ├── settings-checkbox-spec.md ├── nsindicator-spec.md ├── memberItem-spec.md ├── settings-menu-select-spec ├── alertLogItem-spec.md ├── alertItem-spec.md ├── vidcontrolsadmin-spec.md ├── dialpad-spec.md ├── vidcontrolsuser-spec.md ├── callprogress-spec.md ├── callhistory-spec.md └── browser-spec.md ├── images ├── Verto-logo.png └── FreeSwitch-Logo.png ├── README.md ├── webpack.config.js └── package.json /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | .DS_Store 3 | src/bundle.js 4 | src/vendors.js 5 | dist/* 6 | verto.tar 7 | -------------------------------------------------------------------------------- /documents/img/chi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/chi.png -------------------------------------------------------------------------------- /images/Verto-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/images/Verto-logo.png -------------------------------------------------------------------------------- /documents/img/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/input.png -------------------------------------------------------------------------------- /documents/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/login.png -------------------------------------------------------------------------------- /src/img/Verto-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/src/img/Verto-logo.png -------------------------------------------------------------------------------- /documents/img/dialpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/dialpad.png -------------------------------------------------------------------------------- /documents/img/nsi-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/nsi-icon.png -------------------------------------------------------------------------------- /documents/img/nsi-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/nsi-menu.png -------------------------------------------------------------------------------- /documents/img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/preview.png -------------------------------------------------------------------------------- /documents/img/um-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/um-icon.png -------------------------------------------------------------------------------- /documents/img/um-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/um-menu.png -------------------------------------------------------------------------------- /images/FreeSwitch-Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/images/FreeSwitch-Logo.png -------------------------------------------------------------------------------- /documents/img/Status-Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/Status-Icon.png -------------------------------------------------------------------------------- /documents/img/about-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/about-img.png -------------------------------------------------------------------------------- /documents/img/admin-img 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/admin-img 2.png -------------------------------------------------------------------------------- /documents/img/admin-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/admin-img.png -------------------------------------------------------------------------------- /documents/img/alertItem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/alertItem.png -------------------------------------------------------------------------------- /documents/img/alertList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/alertList.png -------------------------------------------------------------------------------- /documents/img/callhistory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/callhistory.png -------------------------------------------------------------------------------- /documents/img/chaltstate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/chaltstate.png -------------------------------------------------------------------------------- /documents/img/numberpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/numberpad.png -------------------------------------------------------------------------------- /src/img/FreeSwitch-Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/src/img/FreeSwitch-Logo.png -------------------------------------------------------------------------------- /documents/img/alertLog-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/alertLog-full.png -------------------------------------------------------------------------------- /documents/img/alertLogItem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/alertLogItem.png -------------------------------------------------------------------------------- /documents/img/chatinput-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/chatinput-img.png -------------------------------------------------------------------------------- /documents/img/contributors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/contributors.png -------------------------------------------------------------------------------- /documents/img/progress-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/progress-img.png -------------------------------------------------------------------------------- /documents/img/verto-appbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/verto-appbar.png -------------------------------------------------------------------------------- /documents/img/volume-meter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/volume-meter.png -------------------------------------------------------------------------------- /documents/img/Template-Image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/Template-Image.png -------------------------------------------------------------------------------- /documents/img/alertLog-noData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/alertLog-noData.png -------------------------------------------------------------------------------- /documents/img/contributors-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/contributors-img.png -------------------------------------------------------------------------------- /documents/img/lastcall-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/lastcall-example.png -------------------------------------------------------------------------------- /documents/img/memberItem-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/memberItem-img.png -------------------------------------------------------------------------------- /documents/img/memberList-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/memberList-img.png -------------------------------------------------------------------------------- /documents/img/preview-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/preview-settings.png -------------------------------------------------------------------------------- /documents/img/splash-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/splash-screenshot.png -------------------------------------------------------------------------------- /documents/img/Settings-image-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/Settings-image-full.png -------------------------------------------------------------------------------- /documents/img/chatmessageitem-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/chatmessageitem-img.png -------------------------------------------------------------------------------- /documents/img/chatmessagelist-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/chatmessagelist-img.png -------------------------------------------------------------------------------- /documents/img/settings-cbox-checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-cbox-checked.png -------------------------------------------------------------------------------- /documents/img/vcstatus-conencting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/vcstatus-conencting.png -------------------------------------------------------------------------------- /documents/img/vcstatus-disconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/vcstatus-disconnected.png -------------------------------------------------------------------------------- /documents/img/floor-presenter-badges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/floor-presenter-badges.png -------------------------------------------------------------------------------- /documents/img/settings-cbox-unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-cbox-unchecked.png -------------------------------------------------------------------------------- /documents/img/settings-preview-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-preview-modal.png -------------------------------------------------------------------------------- /documents/img/settings-menuSelect-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-menuSelect-open.png -------------------------------------------------------------------------------- /documents/img/splashmessage-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/splashmessage-screenshot.png -------------------------------------------------------------------------------- /documents/img/floorlocked-presenter-badges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/floorlocked-presenter-badges.png -------------------------------------------------------------------------------- /documents/img/settings-menuSelect-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-menuSelect-default.png -------------------------------------------------------------------------------- /documents/img/settings-video-secondary-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/star2star/react-verto-communicator/HEAD/documents/img/settings-video-secondary-menu.png -------------------------------------------------------------------------------- /src/js/whitelabel.js: -------------------------------------------------------------------------------- 1 | const data = require("./whitelabelData.js"); 2 | 3 | export default class WhiteLabel { 4 | static get(id) { 5 | if (data[id]) { 6 | return data[id]; 7 | } else { 8 | console.error(`Missing Key ${id} from whitelabel.json`); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/containers/reducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { app } from './appbar/reducers'; 3 | import { auth } from './main/auth-reducers'; 4 | import { callInfo } from './main/callInfo-reducer'; 5 | import { reducer as tooltip } from 'redux-tooltip'; 6 | 7 | export default combineReducers({ 8 | app, 9 | auth, 10 | callInfo, 11 | tooltip 12 | }); 13 | -------------------------------------------------------------------------------- /src/containers/appbar/action-creators.js: -------------------------------------------------------------------------------- 1 | const doSubmitSettings = (data) => { 2 | return { 3 | type: 'APP_SUBMIT_SETTINGS', 4 | data: data 5 | }; 6 | }; 7 | 8 | const doUpdateSetting = (settingObj) => { 9 | return { 10 | type: 'APP_UPDATE_SINGLE_SETTING', 11 | data: settingObj 12 | }; 13 | }; 14 | 15 | const doGetSettings = (data) => { 16 | return { 17 | type: 'APP_GET_SETTINGS', 18 | data: data 19 | }; 20 | }; 21 | 22 | export { doSubmitSettings, doUpdateSetting, doGetSettings }; 23 | -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | overflow: hidden; 5 | padding: 0; 6 | margin: 0; 7 | 8 | font-family: RobotoDraft,Roboto,"Helvetica Neue",Helvetica,Arial,sans-serif; 9 | } 10 | body { /* can also be whatever container */ 11 | display: flex; 12 | display: -webkit-flex; 13 | display: flex; 14 | -webkit-align-items: center; 15 | align-items: center; 16 | -webkit-justify-content: center; 17 | justify-content: center; 18 | } 19 | #app { 20 | height: 100%; 21 | width: 100%; 22 | } 23 | .active { 24 | color: green; 25 | } 26 | -------------------------------------------------------------------------------- /src/js/whitelabelData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const whitelabelData = { 3 | "appName" : "Verto Communicator", 4 | "ieDownloadURL" : "https://www.microsoft.com/en-us/download/internet-explorer.aspx", 5 | "chromeDownloadURL" : "https://www.google.com/chrome/browser/desktop/", 6 | "firefoxDownloadURL" : "https://www.mozilla.org/en-US/firefox/new", 7 | "safariDownloadURL" : "https://support.apple.com/downloads/safari", 8 | "logoSrc" : "./img/Verto-logo.png", 9 | "poweredBy" : "./img/FreeSwitch-Logo.png" 10 | }; 11 | module.exports = whitelabelData; 12 | -------------------------------------------------------------------------------- /src/tests/browser-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | //import TestUtils from 'react-addons-test-utils'; 7 | 8 | import BNS from '../components/browser.js'; 9 | 10 | jest.unmock('../components/browser.js'); 11 | 12 | describe('Browser Not Supported Component', ()=>{ 13 | 14 | it('renders tag', () => { 15 | 16 | //expect(true).toBe(true); 17 | 18 | const wrapper = shallow(); 19 | console.log('bns wrapper', wrapper.nodes); 20 | expect(wrapper.find('div').length).toEqual(1); 21 | 22 | }); 23 | 24 | //TODO add more tests... 25 | }); 26 | -------------------------------------------------------------------------------- /src/tests/lastcall-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import LastCall from '../components/lastCall.js'; 6 | 7 | jest.unmock('../components/lastCall.js'); 8 | 9 | describe('LastCall', ()=>{ 10 | 11 | it('properly takes in a phone number', () => { 12 | const wrapper = mount(); 13 | //console.log(wrapper.props().lastNumber); 14 | expect(wrapper.props().lastNumber).toEqual("867-5309"); 15 | }); 16 | 17 | it('properly takes in a label', () => { 18 | const wrapper = mount(); 19 | expect(wrapper.props().labelText).toEqual("In Call: "); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | react-verto-communicator 2 | ======================== 3 | 4 | Requires node.js version 4 or higher to run build 5 | 6 | Step 1 - clone repository 7 | ------------------------- 8 | 9 | ```javascript 10 | git clone https://github.com/star2star/react-verto-communicator.git 11 | 12 | ``` 13 | 14 | Step 2 - do an npm install to download all required packages 15 | ------------------------------------------------------------ 16 | 17 | ```javascript 18 | npm install 19 | ``` 20 | 21 | Step 3 - run in dev mode 22 | ------------------------ 23 | 24 | Listens on port 8080 ... http://localhost:8080 25 | 26 | ```javascript 27 | npm start 28 | ``` 29 | 30 | Step 4 - production build 31 | ------------------------- 32 | 33 | produces a verto.tar in the current directory 34 | 35 | ```javascript 36 | npm run build 37 | ``` 38 | -------------------------------------------------------------------------------- /src/js/contributorService.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | import md5 from 'md5'; 4 | import contribData from '../config/contributorsData'; 5 | import url from 'url'; 6 | 7 | let _instance; 8 | 9 | class ContributorService { 10 | constructor(){ 11 | //console.log('>>>>', ); 12 | this.contributorsData = contribData.map((contrib)=>{ 13 | return {...contrib, avatar: url.parse(location.href).protocol + "//gravatar.com/avatar/" + md5(contrib.email) + ".png?s=75"}; 14 | }); 15 | 16 | //ContributorService.getContributors = ContributorService.getContributors.bind(this); 17 | } 18 | 19 | getContributors(){ 20 | return this.contributorsData; 21 | } 22 | 23 | static getInstance() { 24 | if (!_instance) { 25 | _instance = new ContributorService(); 26 | } 27 | 28 | return _instance; 29 | } 30 | 31 | } 32 | 33 | //exporting 34 | export default ContributorService; 35 | -------------------------------------------------------------------------------- /src/tests/vcstatus-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | //import TestUtils from 'react-addons-test-utils'; 8 | 9 | import VCStatus from '../components/vcstatus.js'; 10 | 11 | jest.unmock('../components/vcstatus.js'); 12 | jest.unmock('../components/svgIcons.js'); 13 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 14 | jest.unmock('../js/messages.js'); 15 | jest.unmock('moment'); 16 | 17 | describe('Verto Comm Status Component', ()=>{ 18 | 19 | it('renders tag', () => { 20 | //expect(true).toBe(true); 21 | const wrapper = shallowWithIntl(); 22 | expect(wrapper.find('StatusIconSVG').length).toEqual(0); 23 | }); 24 | 25 | //TODO add more tests... 26 | }); 27 | -------------------------------------------------------------------------------- /src/tests/login-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | //import { shallow, mount, render } from 'enzyme'; 4 | //import sinon from 'sinon'; 5 | //import ReactDOM from 'react-dom'; 6 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | 8 | import Login from '../components/login.js'; 9 | 10 | jest.unmock('../components/login.js'); 11 | jest.unmock('../components/input.js'); 12 | //jest.unmock('../containers/appbar/index.js'); 13 | //jest.unmock('../main.js'); 14 | 15 | describe('', ()=>{ 16 | const settings = { 17 | name : 'kc nichols', 18 | email : 'knichols@star2star.com', 19 | user : 'kc', 20 | password : '1234', 21 | callerid : 'KC Nichols', 22 | hostname : 'gator', 23 | websocketurl : 'www.kc.com' 24 | }; 25 | //const intl = 26 | 27 | 28 | it('displays a label', () => { 29 | const wrapper = shallowWithIntl(); 30 | // console.log('%%%%%%%%%%%%%%%%%%%%', wrapper); 31 | //expect(wrapper.get(0).props.settings).toEqual(settings); 32 | }); 33 | 34 | }); 35 | -------------------------------------------------------------------------------- /src/tests/splashmessage-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | //import TestUtils from 'react-addons-test-utils'; 7 | import SplashMessage from '../components/splashmessage.js'; 8 | 9 | jest.unmock('../components/splashmessage.js'); 10 | 11 | describe('Splash Screen Message Component', ()=>{ 12 | 13 | it('renders 2
tags if errorObject is not passed into it', () => { 14 | //expect(true).toBe(true); 15 | const wrapper = shallow( 16 | ); 17 | expect(wrapper.find('div').length).toEqual(2 ); 18 | }); 19 | 20 | it('renders 5
tags if errorObject is passed into it', () => { 21 | //expect(true).toBe(true); 22 | const wrapper = shallow( 23 | ); 24 | expect(wrapper.find('div').length).toEqual(5); 25 | }); 26 | 27 | //end of the tests 28 | }); 29 | -------------------------------------------------------------------------------- /src/tests/alertList-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import AlertList from '../components/alertList'; 7 | import AlertItem from '../components/alertItem'; 8 | 9 | jest.unmock('../components/alertItem'); 10 | jest.unmock('../components/alertList'); 11 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 12 | 13 | 14 | describe('Default test for AlertList', ()=>{ 15 | 16 | const cbDismissAlert = sinon.spy(); 17 | const sampleData = { 18 | level:"warn", 19 | timestamp:1466703201123, 20 | summary: "Can't hang up while sharing screen", 21 | detail: "You must stop sharing your screen before you can hangup the call", 22 | id: 0 23 | }; 24 | const sampleKey = { 25 | id: 0 26 | }; 27 | 28 | 29 | it('renders a div', () => { 30 | const wrapper = shallow( 31 | ); 33 | expect(wrapper.find('div').length).toEqual(1); 34 | }); 35 | 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /documents/volumeMeter-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: volumeMeter # 2 | # 1. Functional Description # 3 | 4 | This component displays a 'meter' indicating relative volume for the audio setting. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A sample about page](img/volume-meter.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the style for this component | 19 | |volumeLevel| volumeLevel= 0| This prop is a number expected to between 0 and 100. If a number > 100 is entered, all level segments will be filled, and if a number less than 0 is entered, no level segments will be filled. 20 | 21 | 22 | ## b. Component State ## 23 | This is a 'pure' component. 24 | 25 | ## c. Context-Aware Specification ## 26 | 27 | This component is a 'pure' component. 28 | 29 | # 4. Reference Components # 30 | 31 | * vertobase component 32 | 33 | # 5. Unit Testing Requirement # 34 | 35 | Tests can be found in src/tests 36 | -------------------------------------------------------------------------------- /src/components/badge.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | compStyle: React.PropTypes.object, 6 | cbClick : React.PropTypes.func, 7 | count : React.PropTypes.number 8 | }; 9 | 10 | class Badge extends VertoBaseComponent { 11 | constructor(props){ 12 | super(props); 13 | this.state = {}; 14 | } 15 | 16 | 17 | 18 | getDefaultStyle(styleName) { 19 | const styles = { 20 | badgeStyles: { 21 | zIndex: '3', 22 | margin: '5px', 23 | backgroundColor: '#D0021B', 24 | borderRadius: '75px', 25 | padding: '4px 8px', 26 | color: '#fff ', 27 | display: 'flex', 28 | justifyContent: 'center', 29 | alignItems: 'center', 30 | fontFamily: 'sans-serif' 31 | } 32 | }; 33 | 34 | return styles[styleName]; 35 | } 36 | 37 | render(){ 38 | return( 39 | 40 | 41 | {this.props.count} 42 | 43 | 44 | ); 45 | } 46 | } 47 | 48 | Badge.propTypes = propTypes; 49 | export default Badge; 50 | -------------------------------------------------------------------------------- /documents/contributors-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Contributors # 2 | # 1. Functional Description # 3 | 4 | The Contributors component is a modal that displays a user avatar, name, and email. 5 | 6 | # 3. Visual Design # 7 | 8 | ![A breakdown of how this component looks](./img/contributors.png) 9 | 10 | # 4. Component Type # 11 | 12 | _This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | compStyle | _NOTE styles are in JSX, not CSX_ { inputWrapStyle: {backgroundColor: '#ddd'} inputStyle {fontSize: '1rem'} }m | Sample: | 19 | 20 | ## b. Component State ## 21 | 22 | This component will not maintain its own state. It will change as new prop values are passed into it from its parent. 23 | 24 | ## c. Component Events ## 25 | 26 | Event | Action(s) 27 | ------------ | ------------- 28 | "" | "" 29 | 30 | ## d. Context-Aware Specification ## 31 | 32 | This component is NOT a context-aware component. 33 | 34 | # 5. Reference Components # 35 | 36 | - react-intl 37 | - Modal 38 | - App 39 | 40 | # 6. Unit Testing Requirement # 41 | 42 | - This component does accept styles as a prop. 43 | -------------------------------------------------------------------------------- /src/tests/chatinput-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import ChatInput from '../components/chatinput'; 7 | 8 | jest.unmock('../components/chatinput.js'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | 12 | describe('Default test for VolumeMeter', ()=>{ 13 | 14 | it('renders the input feild', () => { 15 | const wrapper = shallow(); 16 | expect(wrapper.find('input').length).toEqual(1); 17 | }); 18 | 19 | it('triggers an event when the enter key is pressed', () => { 20 | const onClickStub = sinon.spy(); 21 | const wrapper = mount(); 22 | const chatinp = (wrapper.children().first().find('input')); 23 | chatinp.simulate('keyPress'); 24 | expect(onClickStub.calledOnce, true); 25 | }); 26 | 27 | it('renders the container for the input', () => { 28 | const wrapper = shallow(); 29 | expect(wrapper.find('div').length).toEqual(1); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /src/tests/userMenu-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | import Settings from '../components/settings.js'; 8 | 9 | import UserMenu from '../components/userMenu.js'; 10 | 11 | jest.unmock('../components/userMenu.js'); 12 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 13 | jest.unmock('../js/messages.js'); 14 | 15 | describe('', ()=>{ 16 | 17 | // If displayDropdown is true it renders CaretUpIconSVG. 18 | it('renders CaretUpIconSVG if displayDropdown is true', () => { 19 | const wrapper = shallowWithIntl(); 20 | wrapper.setState({ dropdownDisplayed: true}); 21 | expect(wrapper.find('CaretUpIconSVG').length).toEqual(0); 22 | }); 23 | 24 | //If displayDropdown is false it renders CaretDownIconSVG. 25 | it('renders CaretDownIconSVG if displayDropdown is true', () => { 26 | const wrapper = shallowWithIntl(); 27 | wrapper.setState({ dropdownDisplayed: false}); 28 | expect(wrapper.find('CaretDownIconSVG').length).toEqual(0); 29 | }); 30 | 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /src/components/menuItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent.js'; 3 | import Radium from 'radium'; 4 | 5 | const propTypes = { 6 | compStyle : React.PropTypes.object 7 | }; 8 | 9 | const defaultProps = { 10 | allowDisplayDetails : false 11 | }; 12 | 13 | class MenuItem extends VertoBaseComponent { 14 | constructor(props) { 15 | super(props); 16 | } 17 | 18 | 19 | 20 | getDefaultStyle(styleName) { 21 | const styles = { 22 | container: { 23 | display: 'flex', 24 | position: 'relative' 25 | }, 26 | li: { 27 | color: '#333', 28 | padding: '5px 20px', 29 | fontFamily: 'sans-serif', 30 | cursor: 'pointer', 31 | ':hover': { 32 | color: '#009688' 33 | } 34 | } 35 | 36 | }; 37 | 38 | return (styles[styleName]); 39 | } 40 | 41 | render() { 42 | return ( 43 |
47 | {this.props.label} 48 |
49 | ); 50 | } 51 | } 52 | 53 | MenuItem.propTypes = propTypes; 54 | MenuItem.defaultProps = defaultProps; 55 | export default Radium(MenuItem); 56 | // reviewed on 7/14/2016 57 | -------------------------------------------------------------------------------- /documents/about-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: about # 2 | # 1. Functional Description # 3 | 4 | This component displays information about the product. This information includes: the product's logo, the version number, the git revision, and what powers the project. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A sample about page](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/about-img.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | versionNumber | " 0.1.0 " | This prop is a string and is not required. This is what will display directly underneath the project's logo. This tells the user what version of the program they are on.| 19 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the style for this component | 20 | 21 | ## b. Component State ## 22 | 23 | This is a 'pure' component. 24 | 25 | ## c. Context-Aware Specification ## 26 | 27 | This component is a 'pure' component. 28 | 29 | # 4. Reference Components # 30 | 31 | * vertobase component 32 | 33 | # 5. Unit Testing Requirement # 34 | 35 | Tests can be found in src/tests 36 | -------------------------------------------------------------------------------- /documents/chatmessageitem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: chatmessageitem # 2 | # 1. Functional Description # 3 | 4 | This component creates the visual representation of a chat message inside the communicator. 5 | 6 | # 2. Visual Design # 7 | 8 | ![An exanple of a chat input field , taken from the 'original' verto ](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/chatmessageitem-img.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | message | message = {} | This prop is an object and is not required. This object contains the information necessary to print out the full chat message. | 19 | | compStyle | compStyle={} | This prop is an object and it styles the chat message item component. | 20 | 21 | 22 | ## b. Component State ## 23 | 24 | This component will maintain it's own state for presentational purposes. 25 | 26 | ## c. Context-Aware Specification ## 27 | 28 | his component is NOT a context-aware component 29 | 30 | # 5. Reference Components # 31 | 32 | - vertobase 33 | - svgIcons 34 | 35 | # 6. Unit Testing Requirement # 36 | 37 | Tests can be found in src/tests. 38 | -------------------------------------------------------------------------------- /src/components/tooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip, Origin } from 'redux-tooltip'; 3 | import VertoBaseComponent from './vertobasecomponent'; 4 | 5 | const propTypes = { 6 | auto: React.PropTypes.bool, 7 | place: React.PropTypes.string.isRequired, 8 | name: React.PropTypes.string.isRequired, 9 | msg: React.PropTypes.oneOfType([ 10 | React.PropTypes.string, 11 | React.PropTypes.object ]).isRequired, 12 | within: React.PropTypes.func, 13 | compStyle: React.PropTypes.object 14 | }; 15 | 16 | class ToolTip extends VertoBaseComponent { 17 | constructor(props){ 18 | super(props); 19 | } 20 | 21 | 22 | 23 | getDefaultStyle(styleName) { 24 | const styles = { 25 | }; 26 | 27 | return styles[styleName]; 28 | } 29 | 30 | render(){ 31 | return( 32 | 33 | 34 | 35 | {this.props.children} 36 | 37 | 38 | {this.props.msg} 39 | 40 | 41 | );} 42 | } 43 | 44 | ToolTip.propTypes = propTypes; 45 | export default ToolTip; 46 | // reviewed on 7/14/2016 47 | -------------------------------------------------------------------------------- /src/helpers/intl-enzyme-test-helper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Components using the react-intl module require access to the intl context. 3 | * This is not available when mounting single components in Enzyme. 4 | * These helper functions aim to address that and wrap a valid, 5 | * English-locale intl context around them. 6 | */ 7 | 8 | import React from 'react'; 9 | import { IntlProvider, intlShape } from 'react-intl'; 10 | import { mount, shallow } from 'enzyme'; 11 | import messages from '../locales/locale-en.js'; 12 | 13 | 14 | // Create the IntlProvider to retrieve context for wrapping around. 15 | const intlProvider = new IntlProvider({ locale: 'en', messages }, {}); 16 | const { intl } = intlProvider.getChildContext(); 17 | 18 | /** 19 | * When using React-Intl `injectIntl` on components, props.intl is required. 20 | */ 21 | function nodeWithIntlProp(node) { 22 | return React.cloneElement(node, { intl }); 23 | } 24 | 25 | function shallowWithIntl(node) { 26 | console.log('shallowwithintl node',node); 27 | return shallow(nodeWithIntlProp(node), { context: { intl } }); 28 | } 29 | 30 | function mountWithIntl(node) { 31 | return mount(nodeWithIntlProp(node), { 32 | context: { intl }, 33 | childContextTypes: { intl: intlShape } 34 | }); 35 | } 36 | 37 | export {shallowWithIntl, mountWithIntl}; 38 | -------------------------------------------------------------------------------- /src/3rd-party/jquery.cookie.1.4.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jquery.cookie v1.4.1 | MIT */ 2 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}}); 3 | -------------------------------------------------------------------------------- /src/config/contributorsData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const contributors = [ 3 | { 4 | "name": "James Schimmoeller", 5 | "email": "jschimmoeller@star2star.com" 6 | }, 7 | { 8 | "name": "Tom Athens", 9 | "email": "tathens@star2star.com" 10 | }, 11 | { 12 | "name": "Duncan Neal", 13 | "email": "dneal@star2star.com" 14 | }, 15 | { 16 | "name": "KC Nichols", 17 | "email": "knichols@star2star.com" 18 | }, 19 | { 20 | "name": "Brian Hinton", 21 | "email": "bhinton@star2star.com" 22 | }, 23 | { 24 | "name": "Cory Schimmoeller", 25 | "email": "cschimmoeller@star2star.com" 26 | }, 27 | { 28 | "name": "Jonatas Oliveira", 29 | "email": "jonatas@evolux.net.br" 30 | }, 31 | { 32 | "name": "Ítalo Rossi", 33 | "email": "italo@evolux.net.br" 34 | }, 35 | { 36 | "name": "Stefan Yohansson", 37 | "email": "stefan@evolux.net.br" 38 | }, 39 | { 40 | "name": "Victor Torres", 41 | "email": "victor@evolux.net.br" 42 | }, 43 | { 44 | "name": "João Mesquita", 45 | "email": "jmesquita@indicium.com.ar" 46 | }, 47 | { 48 | "name": "Ken Rice", 49 | "email": "krice@freeswitch.org" 50 | }, 51 | { 52 | "name": "Brian West", 53 | "email": "brian@freeswitch.org" 54 | } 55 | ]; 56 | 57 | module.exports = contributors; 58 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | FreeSWITCH Verto™ Video Transcoding 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /documents/browser-info-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: BrowserInfo # 2 | 3 | # 1. Functional Description # 4 | 5 | The BrowserInfo component is a basic component with accessibility features. The component renders a **browserData** object which contains the browser Icon, Name of the browser, Link to download said browser in a new window, & the compatible Versions accepted. The component styles can be adjusted through the **compStyle** prop. 6 | 7 | # 2. Visual Design # 8 | 9 | Images: TBA 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | |------------ | -------------- | ------------| 19 | |browserData | browserData={
icon: ChromeBrowserIconSVG,
link:"https://www.google.com/chrome/browser/desktop/",
name: "Chrome",
versions: "All"
} |An object. Required. Contains browser info | 20 | |compStyle | compStyle={} | An object| 21 | 22 | ## b. Component State ## 23 | 24 | This component is a pure component and it will not maintain it’s own state. 25 | 26 | ## c. Component Events ## 27 | 28 | None. 29 | 30 | ## d. Context-Aware Specification ## 31 | 32 | This component is a pure component and it will not maintain it’s own state. 33 | 34 | # 4. Reference Components # 35 | 36 | - VertoBaseComponent 37 | 38 | # 5. Unit Testing # 39 | 40 | src/tests/browserInfo-test.js 41 | -------------------------------------------------------------------------------- /src/tests/input-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | import Input from '../components/input.js'; 7 | 8 | jest.unmock('../components/input.js'); 9 | 10 | describe('', ()=>{ 11 | const label = "Name"; 12 | const placeHolder = "Your Name"; 13 | const value = "Harry"; 14 | const typ = "password"; 15 | 16 | it('displays a label', () => { 17 | const wrapper = mount(); 18 | //console.log('%%%%%%%%%%%%%%%%%%%%', wrapper.get(0).props.label); 19 | expect(wrapper.get(0).props.label).toEqual(label); 20 | }); 21 | 22 | it('displays a placeholder', () => { 23 | const wrapper = mount(); 24 | expect(wrapper.get(0).props.placeholder).toEqual(placeHolder); 25 | }); 26 | 27 | it('displays a type', () => { 28 | const wrapper = mount(); 29 | expect(wrapper.get(0).props.type).toEqual(typ); 30 | }); 31 | 32 | it('displays a value', () => { 33 | const wrapper = mount(); 34 | expect(wrapper.get(0).props.value).toEqual(value); 35 | }); 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /documents/memberList-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: MemberList # 2 | # 1. Functional Description # 3 | 4 | This component creates the list of member items. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A visual example of MemberList](img/memberList-img.png) 9 | 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | 18 | | Prop Name | Sample | Description | 19 | | ------------ | ------------- | ------------- | 20 | | allowPresenter | allowPresenter = { true } | Boolean. Not required. This prop toggles presenter | 21 | | compStyle | compStyle = {} | This prop provides style for the the member list. | 22 | | hasMultipleCanvases | hasMultipleCanvases = { true } | Boolean. Not required. This prop toggles multiple canvases | 23 | | members | members = [] | Array. Not required. Contains list of current members | 24 | | isModerator | isModerator = { true } | Boolean. Not required. This prop toggles moderator status. | 25 | 26 | 27 | ## b. Component State ## 28 | 29 | This component will maintain it's own state for presentational purposes. 30 | 31 | ## c. Context-Aware Specification ## 32 | 33 | his component is NOT a context-aware component 34 | 35 | # 4. Reference Components # 36 | 37 | - VertoBaseComponent 38 | - MemberItem 39 | 40 | # 6. Unit Testing Requirement # 41 | Tests for this component are located at: 42 | 43 | src/tests/memberList-test.js 44 | -------------------------------------------------------------------------------- /src/tests/chatmessageitem-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import ChatMessageItem from '../components/chatMessageItem'; 7 | import moment from 'moment'; 8 | 9 | jest.unmock('../components/chatMessageItem'); 10 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 11 | jest.unmock('../js/messages.js'); 12 | jest.unmock('moment'); 13 | 14 | describe('Default test for ChatMessageItem', ()=>{ 15 | 16 | const sampleData = { 17 | bgColor: "#FFFFFF", 18 | callID: "1f898d4d-07dd-0988-0436-d65298735c0e", 19 | displayName: "Cory", 20 | isMe: true, 21 | message:"Hi", 22 | utc_timestamp: 1465846699477 23 | }; 24 | 25 | it('renders the correct timestamp ', () => { 26 | const wrapper = shallow(); 27 | //console.log(wrapper.childAt(1).childAt(2).props().children[2]); 28 | expect(wrapper.childAt(1).childAt(2).props().children[2]); 29 | }); 30 | 31 | it('renders the correct username ', () => { 32 | const wrapper = shallow(); 33 | //console.log(wrapper.childAt(1).childAt(2).props().children[2]); 34 | expect(wrapper.childAt(1).childAt(2).props().children[0]).toEqual('Cory'); 35 | }); 36 | 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /documents/chatmessagelist-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: ChatMessageList # 2 | # 1. Functional Description # 3 | 4 | This component creates the list list of all the chat messages. It also provides a user's messages with their chosen avatar image. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A sample of a chat session](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/chatmessagelist-img.png) 9 | 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | 18 | | Prop Name | Sample | Description | 19 | | ------------ | ------------- | ------------- | 20 | | chatItems| chatItems = {} | This prop is an object and is not required. This prop contains the information for each message in the chat. | 21 | | compStyle | compStyle = {} | This prop provides style for the the chat list. | 22 | | chatUsers | chatUsers = {} | This prop is an object and is not required. This object contains the names of all the users who are currently in a particular chat session | 23 | 24 | 25 | ## b. Component State ## 26 | 27 | This component will maintain it's own state for presentational purposes. 28 | 29 | ## c. Context-Aware Specification ## 30 | 31 | his component is NOT a context-aware component 32 | 33 | # 4. Reference Components # 34 | 35 | - vertobase 36 | - chatmessageitem 37 | 38 | # 6. Unit Testing Requirement # 39 | 40 | tests can be found in src/tests 41 | -------------------------------------------------------------------------------- /src/components/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import VertoBaseComponent from './vertobasecomponent'; 4 | 5 | import Main from '../containers/main/index.js'; 6 | import AppBar from '../containers/appbar/index.js'; 7 | 8 | class App extends VertoBaseComponent { 9 | constructor(props){ 10 | super(props); 11 | this.state = {isModalOpen: false}; 12 | this.modal = undefined; 13 | App.toggleModal = this.toggleModal.bind(this); 14 | } 15 | 16 | toggleModal(aModal){ 17 | //console.log('aaaaa') 18 | if (!this.state.isModalOpen) { 19 | this.modal = aModal; 20 | } else { 21 | this.modal = undefined; 22 | } 23 | 24 | this.setState({ ...this.state, isModalOpen: !this.state.isModalOpen }); 25 | } 26 | 27 | 28 | 29 | getDefaultStyle(styleName) { 30 | const styles = { 31 | appStyles: { 32 | display: 'flex', 33 | flexDirection: 'column', 34 | justifyContent: 'flex-start', 35 | height: '100vh', // want to fill the whole screen height 36 | width: '100vw' // and fill screen width 37 | } 38 | }; 39 | 40 | return (styles[styleName]); 41 | } 42 | 43 | render(){ 44 | return ( 45 |
46 | 47 |
48 | {this.modal} 49 | 50 |
); 51 | 52 | } 53 | } 54 | 55 | export default App; 56 | // reviewed 7/13/2016 57 | -------------------------------------------------------------------------------- /src/tests/contributors-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import Contributors from '../components/contributors'; 7 | 8 | jest.unmock('../components/contributors'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | 12 | describe('Default test for Contributors', ()=>{ 13 | const sampleData=[ 14 | {name: "Matt", email: "Matt@matt.com", avatar: "../../pic.png"} 15 | ]; 16 | 17 | it ('prints the right number of statements given one object', () => { 18 | const wrapper = shallowWithIntl({}}/>); 19 | expect(wrapper.find('div').length).toEqual(2); 20 | }); 21 | 22 | it ('renders the modal', () => { 23 | const wrapper = shallowWithIntl({}}/>); 24 | expect(wrapper.find('Modal').length).toEqual(1); 25 | }); 26 | 27 | it('ensures the style is being applied proporly by cheking for one paticular value', () => { 28 | const wrapper = shallowWithIntl({}}/>); 29 | console.log(wrapper.props().style.content.right); 30 | expect(wrapper.props().style.content.right).toEqual('auto'); 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /src/tests/numberitem-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | //import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | 8 | import Numberitem from '../components/numberitem.js'; 9 | 10 | jest.unmock('../components/numberitem.js'); 11 | // jest.unmock('../helpers/intl-enzyme-test-helper.js'); 12 | // jest.unmock('../js/messages.js'); 13 | 14 | describe('', ()=>{ 15 | const cbTest = sinon.spy(); 16 | 17 | // networkData prop is provided. 18 | it('renders keyValue', () => { 19 | const wrapper = mount(); 20 | //console.log('**********************', wrapper.props()); 21 | expect(wrapper.props().keyValue).toEqual('3'); 22 | 23 | }); 24 | 25 | it('renders keyString', () => { 26 | const wrapper = mount(); 27 | //console.log('**********************', wrapper.children()); 28 | expect(wrapper.props().keyString).toEqual('DEF'); 29 | 30 | }); 31 | 32 | //TODO: figure out why click tests aren't working 33 | it('Click event fires callback function', () => { 34 | const wrapper = shallow(); 35 | wrapper.simulate('click'); 36 | expect(cbTest.calledOnce).toEqual(true); 37 | 38 | }); 39 | 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /src/tests/chatmessagelist-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import ChatMessageList from '../components/chatMessageList'; 7 | import moment from 'moment'; 8 | 9 | jest.unmock('../components/chatMessageList'); 10 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 11 | jest.unmock('../js/messages.js'); 12 | jest.unmock('moment'); 13 | 14 | describe('Default test for ChatMessageList', ()=>{ 15 | 16 | 17 | const itemsSample = [{ 18 | bgColor: "#FFFFFF", 19 | callID: "1f898d4d-07dd-0988-0436-d65298735c0e", 20 | displayName: "Cory", 21 | isMe: true, 22 | message:"Hi", 23 | utc_timestamp: 1465846699477 24 | }]; 25 | 26 | const usersSample = { 27 | avatar: { 28 | avatar: "http://gravatar.com/avatar/2456ab4d05ef8d750b6d7492839e32d7.png?s=75", 29 | email: "Cory@schimmoeller.net" 30 | }, 31 | callerId: "Cory", 32 | codec: "opus@48000", 33 | conferenceStatus: { 34 | memberId: "0361", 35 | name: "Cory" 36 | } 37 | }; 38 | /* 39 | it('does thing ', () => { 40 | const wrapper = shallow(); 41 | expect(wrapper.childAt(1).childAt(2).props().children[2]).toEqual('Today at 3:38 PM'); 42 | }); 43 | 44 | */ 45 | 46 | 47 | 48 | }); 49 | -------------------------------------------------------------------------------- /src/tests/splash-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import TestUtils from 'react-addons-test-utils'; 6 | import {StyleRoot} from 'radium'; 7 | import Splash from '../components/splash.js'; 8 | jest.unmock('../components/splash.js'); 9 | 10 | 11 | describe('Splash Screen Component', ()=>{ 12 | 13 | const sampleStep = { 14 | number: 4, 15 | current: 2, 16 | title: "Checking Media Permissions" 17 | }; 18 | 19 | const sampleStep2 = { 20 | number: 4, 21 | current: 3, 22 | title: "Checking Connection Speed" 23 | }; 24 | 25 | it('renders a given step', () => { 26 | const wrapper = mount(); 27 | expect(wrapper.props().step).toEqual(undefined); 28 | }); 29 | 30 | it('sets the correct width for the loading bar when 2 of 4 steps are completed.', ()=> { 31 | expect(Splash.getProgressBarWidth(sampleStep)).toEqual(50); 32 | }); 33 | 34 | it('sets the correct width for the loading bar when 3 of 4 steps are completed.', ()=> { 35 | expect(Splash.getProgressBarWidth(sampleStep2)).toEqual(75); 36 | }); 37 | 38 | it('uses the SplashMessage component', ()=> { 39 | const wrapper = mount(); 40 | expect(wrapper.find('SplashMessage').props().statusTitle).toEqual('Checking Media Permissions'); 41 | }); 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /src/tests/settingspreview-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import SettingsPreview from '../components/settingsPreview'; 7 | 8 | jest.unmock('../components/settingsPreview'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | 12 | describe('Default test for SettingsPreview', ()=>{ 13 | 14 | const sampleSettingsData = { 15 | askRecoverCall: false, 16 | autoBand: true, 17 | bestFrameRate: { id:"15", label:"15 FPS" }, 18 | googEchoCancellation: true, 19 | googNoiseSuppression: true, 20 | incomingBandwidth: "default", 21 | language:"en", 22 | languages: {id:"en", name:"English"}, 23 | mirrorInput: false, outgoingBandwidth: "default", 24 | selectedAudio: [], 25 | selectedBestFrameRate: [], 26 | selectedShare: [], 27 | selectedSpeaker: [], 28 | selectedVideo: [], 29 | testSpeedJoin: true, 30 | useDedence: false, 31 | useSTUN: true, 32 | useStereo: true, 33 | vidQual:undefined 34 | }; 35 | 36 | 37 | it ('Displays the volume meter', () => { 38 | const wrapper = shallowWithIntl({}} />); 39 | expect(wrapper.find('VolumeMeter').length).toEqual(0); 40 | }); 41 | 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /src/components/browser.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | 6 | }; 7 | 8 | class Browser extends VertoBaseComponent { 9 | constructor(props) { 10 | super(props); 11 | } 12 | 13 | 14 | 15 | getDefaultStyle(styleName) { 16 | const styles = { 17 | browserStyles : { 18 | 19 | }, 20 | pageStyle : { 21 | fontFamily: 'sans-serif', 22 | color: 'gray', 23 | margin: '0rem' 24 | }, 25 | infoContainerStyle : { 26 | margin: '0 auto 0 auto', 27 | width: '44rem' 28 | }, 29 | headerContainerStyle : { 30 | backgroundColor: '#CB6969', 31 | color: '#fff', 32 | minHeight: '30rem', 33 | margin: '0 auto', 34 | fontStyle: 'none', 35 | marginBottom: '4rem' 36 | }, 37 | titleStyle : { 38 | fontSize: '5rem', 39 | textAlign: 'center', 40 | paddingTop: '10rem' 41 | }, 42 | browserIcon : { 43 | margin: '0 ', 44 | padding: '0', 45 | width: '40px', 46 | height: '40px' 47 | } 48 | }; 49 | 50 | return (styles[styleName]); 51 | } 52 | 53 | render() { 54 | return ( 55 |
Browser Not Supported
56 | ); 57 | } 58 | } 59 | 60 | Browser.propTypes = propTypes; 61 | 62 | export default Browser; 63 | // reviewed 7/13/2016 64 | -------------------------------------------------------------------------------- /src/components/list-select.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | items: React.PropTypes.array.isRequired, 6 | selected: React.PropTypes.array, 7 | cbChange: React.PropTypes.func, 8 | compStyle: React.PropTypes.object 9 | }; 10 | 11 | class ListSelect extends VertoBaseComponent { 12 | constructor(props) { 13 | super(props); 14 | } 15 | 16 | 17 | getDefaultStyle(styleName) { 18 | const styles = { 19 | listStyles: { 20 | listStyleType: 'none', 21 | backgroundColor: '#fff', 22 | padding: '0px 10px' 23 | }, 24 | itemStyles: { 25 | margin: '4px 0' 26 | } 27 | }; 28 | return (styles[styleName]); 29 | } 30 | 31 | render() { 32 | const listItems = this.props.items.map((item, index)=>{ 33 | let styles=this.getStyle("itemStyles"); 34 | 35 | if (this.props.selected && this.props.selected == index) { 36 | styles={...this.getStyle("itemStyles"), backgroundColor: '#eee'}; 37 | } 38 | 39 | return ( 40 |
  • {this.props.cbChange(index);}} 42 | > 43 | {item} 44 |
  • 45 | ); 46 | }); 47 | 48 | return (
      49 | {listItems} 50 |
    ); 51 | } 52 | } 53 | 54 | ListSelect.propTypes = propTypes; 55 | 56 | export default ListSelect; 57 | // reviewed on 7/13/2016 58 | -------------------------------------------------------------------------------- /documents/contributorslistitem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: about # 2 | # 1. Functional Description # 3 | 4 | This component displays creates a single list item each time it is called. Each item represents one contributor to a given project. The information on the list items is: the person's name, their name, and their picture. 5 | 6 | # 2. Visual Design # 7 | 8 | ![An example of several contributor list items ](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/contributors-img.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | name | "Matt"| This prop is a string and is required. This string is a given contributor's name. | 19 | | email | "mynameis@matt.com" | This prop is a string and is required. This string is a given contributor's email. | 20 | | avatar | "../../img/avatar/johnIcon.png" | This prop is a string and is required. This string the location of a contributor's avatar. | 21 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the style for this component | 22 | 23 | ## b. Component State ## 24 | 25 | This is a 'pure' component. 26 | 27 | ## c. Context-Aware Specification ## 28 | 29 | This component is a 'pure' component. 30 | 31 | # 4. Reference Components # 32 | 33 | * vertobase component 34 | 35 | # 5. Unit Testing Requirement # 36 | 37 | Tests can be found in src/tests 38 | -------------------------------------------------------------------------------- /src/js/messages.js: -------------------------------------------------------------------------------- 1 | const DIALECTS = { 2 | 'en': 'en', 3 | 'en-gb': 'en', 4 | 'en-us': 'en', 5 | 'it': 'it', 6 | 'it-it': 'it', 7 | 'fr': 'fr', 8 | 'fr-fr': 'fr', 9 | 'fr-ca': 'fr', 10 | 'pt': 'pt', 11 | 'pt-br': 'pt', 12 | 'pt-pt': 'pt', 13 | 'de': 'de', 14 | 'de-de': 'de', 15 | 'es': 'es', 16 | 'es-es': 'es', 17 | 'pl': 'pl', 18 | 'pl-pl': 'pl', 19 | 'ru': 'ru', 20 | 'ru-ru': 'ru', 21 | 'sv': 'sv', 22 | 'sv-sv': 'sv', 23 | 'sv-fi': 'sv', 24 | 'da': 'da', 25 | 'da-dk': 'da', 26 | 'id': 'id', 27 | 'id-id': 'id', 28 | 'zh': 'zh', 29 | 'zh-cn': 'zh', 30 | 'zh-tw': 'zh', 31 | 'zh-hk': 'zh' 32 | }; 33 | 34 | export default class Messages { 35 | constructor(aLocale="en-US") { 36 | this.locale = aLocale; 37 | this.dialect = Messages.getDialect(this.locale.toLowerCase()); 38 | //const localeFile = 'locale-' + this.dialect; 39 | //console.log('^^^^^^', aLocale, this.locale, DIALECTS, this.dialect); 40 | 41 | const messages = require('../locales/locale-'+this.dialect+'.js'); 42 | // console.log('MMEESSAAGGEESS', messages); 43 | this.msg = messages; 44 | 45 | } 46 | 47 | static getDialect(aLocale="en-US") { 48 | 49 | return DIALECTS[aLocale.toLowerCase()]; 50 | } 51 | 52 | getAllMessages(){ 53 | return this.msg; 54 | } 55 | 56 | get(id) { 57 | if (this.msg[id]) { 58 | return this.msg[id]; 59 | } else { 60 | console.error(`Missing Key ${id} from Messages`); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /documents/alertList-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: AlertList # 2 | # 1. Functional Description # 3 | 4 | AlertList is a basic list component that displays the AlertItem components. The alerts will display for 5 seconds then timeout or they can be dismissed by clicking the RemoveIconSVG (the 'x' in the top right corner). 5 | 6 | # 2. Visual Design # 7 | 8 | - Alert List:
    9 | ![Alert List Image](img/alertList.png) 10 | 11 | # 3. Component Type # 12 | 13 | This is a ‘pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | |compStyle | _NOTE styles are in JSX, not CSS_ { alertItemStyles : { display: 'flex',border: '1px solid #d1d1d1', backgroundColor: '#FFF'} } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 20 | 21 | ## b. Component State ## 22 | 23 | ## c .Component Events ## 24 | 25 | | Event | Action(s) | 26 | | ------------ | ------------- | 27 | | 'RemoveIconSVG' clicked | 1. Callback function invoked.
    2. State Change.
    3. Specific alert is removed from alertList. | 28 | 29 | ## d. Context-Aware Specification ## 30 | 31 | This component is a pure component and it will maintain it’s own state. 32 | 33 | # 4. Reference Components # 34 | 35 | The component to be developed requires the following components: 36 | 37 | - VertoBaseComponent 38 | - AlertItem 39 | 40 | # 5. Unit Testing Requirement # 41 | Tests for this component are located at: 42 | 43 | src/tests/alertList-test.js 44 | -------------------------------------------------------------------------------- /documents/splash-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: splashmessage # 2 | # 1. Functional Description # 3 | This component displays the the loading message as well as the progress bar. This component will take in the splashmessage component in order to display what stage of loading the communicator is in. The splashmessage component will also alert the user if there is an error. 4 | 5 | # 2. Visual Design # 6 | 7 | ![An example of what this component will output when it hits an error](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/splash-screenshot.png) 8 | 9 | # 3. Component Type # 10 | 11 | This is a 'pure' component. 12 | 13 | ## a. Required Props ## 14 | 15 | | Prop Name | Sample | Description | 16 | | ------------ | ------------- | ------------- | 17 | | Step | { number: 1, current: 2, title: "Checking media permissions" } | This prop is an object with a particular shape and is required . This object must have the number, current, and title properties. This object contains information about each step the communicator takes when it loads. | 18 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the style for this component | 19 | 20 | ## b. Component State ## 21 | 22 | This is a 'pure' component. 23 | 24 | # c. Context-Aware Specification ## 25 | 26 | This component is a 'pure component'. 27 | 28 | # 4. Reference Components # 29 | 30 | * vertobase component 31 | * splashmessage component 32 | * ReactIntl 33 | 34 | # 5. Unit Testing Requirement # 35 | 36 | Tests can be found in src/tests 37 | -------------------------------------------------------------------------------- /documents/memberadmincontrols-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: messageAdminControls # 2 | # 1. Functional Description # 3 | 4 | This component provides the admin(s) of a given call with a set of options. These options can vary based off of the value of some of the props passed into the component. 5 | 6 | # 2. Visual Design # 7 | 8 | ![An example of the admin controls](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/messageAdminControl-img.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | multCanvas | multCanvas = false | This prop is a boolean and is not required. This prop tells the admin controls component wether or not not there are multiple active canvases. The value of this prop will change what controls get displayed. | 19 | | compStyle | compStyle={} | This prop is an object and is not required, This prop styles the admin controls component. | 20 | | member | member = {} | This prop is an object and is required. This prop provides information on an individual member of the call. | 21 | 22 | ## b. Component State ## 23 | 24 | This component will maintain it's own state for presentational purposes. 25 | 26 | ## c. Context-Aware Specification ## 27 | 28 | This component is NOT a context-aware component 29 | 30 | # 5. Reference Components # 31 | 32 | - vertobase 33 | - svgIcons 34 | 35 | # 6. Unit Testing Requirement # 36 | 37 | Tests can be found in src/tests. 38 | -------------------------------------------------------------------------------- /documents/login-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Login # 2 | # 1. Functional Description # 3 | 4 | The login component is a form to enter specific information. Once it is supplied, the Login button can be clicked. Optionally, the settings link can be clicked and it will display a form to adjust settings. 5 | 6 | # 2. Visual Design # 7 | 8 | ![Login Component](./img/login.png) 9 | 10 | # 3. Component Type # 11 | 12 | The Login component will be a pure component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | settings | settings={
    } | An object that contains settings information. | 19 | | compStyle | compStyle={
    } | An object that contains css styles. | 20 | 21 | [comment]: <> (TODO update object samples once I have the object structure) 22 | 23 | ## b. Component State ## 24 | 25 | This component will maintain it's own state for presentational purposes. 26 | 27 | Initial state: 28 | 29 | this.state = { 30 | advanced: false 31 | settings: this.props.settings 32 | } 33 | 34 | ## c .Component Events ## 35 | 36 | Event | Action(s) 37 | ------------ | ------------- 38 | Login Button Clicked | 1. Invoke the submitLogin function. 39 | 40 | 41 | ## d. Context-Aware Specification ## 42 | 43 | This component is NOT context-aware. 44 | 45 | # 5. Reference Components # 46 | 47 | - VertoBaseComponent 48 | - defineMessages, injectIntl, intlShape, FormattedMessage from react-intl 49 | 50 | 51 | 52 | # 6. Unit Testing Requirement # 53 | 54 | Tests for this component are located at: 55 | 56 | src/tests/login-test.js 57 | -------------------------------------------------------------------------------- /documents/numberpad-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Numberpad # 2 | # 1. Functional Description # 3 | 4 | Numberpad is an area that displays numbers and corresponding characters/symbols used for dialing phone numbers. 5 | 6 | # 3. Visual Design # 7 | 8 | ![Numberpad](./img/numberpad.png) 9 | 10 | # 4. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | compStyle | compStyle={} | compStyle is an optional prop that defines styles for the Numberpad component. | 19 | | cbClick | cbClick={()=>{}}| cbClick is a required function. | 20 | | keyValue | keyValue="2" | keyValue is a required prop that has a string value that is rendered in each numberItem | 21 | | keyString | keyString="ABC" | keyString is a required prop that has a string value that is rendered in each numberItem | 22 | 23 | 24 | ## b. Component State ## 25 | 26 | This component will not maintain its own state. It will change as new prop values are passed into it from its parent. 27 | 28 | ## c .Component Events ## 29 | 30 | 31 | |Event | Action(s)| 32 | |------------ | -------------| 33 | |{NumberItem} clicked | 1 .Invoke the callback function cbClick(). | 34 | 35 | ## d. Context-Aware Specification ## 36 | 37 | This component is NOT context-aware. 38 | 39 | # 5. Reference Components # 40 | 41 | - VertoBaseComponent 42 | - SvgIcons 43 | - Radium 44 | - ReactIntl 45 | 46 | # 6. Unit Testing Requirement # 47 | 48 | - It simulates a click event. 49 | - It renders a keyValue prop. 50 | - It renders a keyString prop. 51 | -------------------------------------------------------------------------------- /src/tests/numberpad-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | //import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | 8 | import Numberpad from '../components/numberpad.js'; 9 | 10 | jest.unmock('../components/numberpad.js'); 11 | jest.unmock('../components/numberitem.js'); 12 | // jest.unmock('../helpers/intl-enzyme-test-helper.js'); 13 | // jest.unmock('../js/messages.js'); 14 | 15 | describe('', ()=>{ 16 | const cbTest = sinon.spy(); 17 | 18 | // networkData prop is provided. 19 | // it('renders keyValue', () => { 20 | // const wrapper = mount(); 21 | // //console.log('**********************', wrapper.props()); 22 | // expect(wrapper.props().keyValue).toEqual('3'); 23 | // 24 | // }); 25 | // 26 | // it('renders keyString', () => { 27 | // const wrapper = mount(); 28 | // //console.log('**********************', wrapper.children()); 29 | // expect(wrapper.props().keyString).toEqual('DEF'); 30 | // 31 | // }); 32 | 33 | //TODO: figure out why click tests aren't working 34 | it('Click event fires callback function', () => { 35 | const wrapper = mount(); 36 | //console.log(wrapper.find('NumberItem')); 37 | //console.log(wrapper.find('NumberItem').first()); 38 | wrapper.find('NumberItem').first().simulate('click'); 39 | expect(cbTest.calledOnce).toEqual(true); 40 | 41 | }); 42 | 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /documents/splashmessage-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: splashmessage # 2 | # 1. Functional Description # 3 | 4 | This component displays the conditions, one at a time, that get checked when the communicator loads. If there is an error, such as a user having access to their webcam blocked or an unsupported browser, an error message will take up the bottom part of the screen. This error message will have a red background, and the text color will change to white. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A sample error message](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/splashmessage-screenshot.png) 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | progressTitle | "Checking media permissions." | This is what will display underneath the loading bar. This provides the user with updates on what the communicator is doing when it is loading.| 19 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the style for this component | 20 | | errorObject | errorObject = {header: "Error", body: "Please enable your webcam and refresh the page" } | This prop is an object and is not required. The contents of this object are used to print out an error message. | 21 | 22 | ## b. Component State ## 23 | 24 | This is a 'pure' component. 25 | 26 | ## c. Context-Aware Specification ## 27 | 28 | This component is a 'pure' component. 29 | 30 | # 4. Reference Components # 31 | 32 | * vertobase component 33 | 34 | # 5. Unit Testing Requirement # 35 | 36 | Tests can be found in src/tests 37 | -------------------------------------------------------------------------------- /documents/appbar-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: AppBar # 2 | # 1. Functional Description # 3 | 4 | The appbar component is a composite component made up of several simpler components. This is a 'smart' component (container) that will have access to a data store using action-creators and reducers (redux). Content of the AppBar component are the App Title (default is 'Verto Communicator'), a network status indicator including a drop down with details, a status indicator that visually shows connection status (only visible after initial connection made), last number called, settings UI toggle (only visible when logged in), user menu with dropdown menu, chat/members toggle (only visible when connected), and an About/Help menu with drop 5 | 6 | # 2. Visual Design # 7 | 8 | Sample: 9 | 10 | ![A breakdown of how this component looks](img/verto-appbar.png) 11 | 12 | # 3. Component Type # 13 | 14 | This is a 'context-aware' component and will maintain state in the store 'app'. 15 | 16 | ## a. Required Props ## 17 | 18 | This component takes no props. 19 | 20 | ## b. Component State ## 21 | The state is maintained in the store 'app' and is updated by dispatching action-creators and updating state via appropriate reducers. The component is subscribe to the store and will re-render appropriately when relevant data in the store is updated. 22 | 23 | 24 | ## c .Component Events ## 25 | This component does not have any events, however its imported components may and they are documented in their respective specifications. 26 | 27 | # 5. Reference Components # 28 | * vcstatus 29 | * vertobasecomponent 30 | * nsIndicator 31 | * userMenu 32 | * tagMenu 33 | * menuItem 34 | * settings 35 | * app 36 | * about 37 | * contributors 38 | -------------------------------------------------------------------------------- /documents/lastcall-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: lastCall # 2 | # 1. Functional Description # 3 | 4 | This component will display, in the appbar, what the last call made was. Display the text 'last call', 'in call', or 'no call' (depending on state) with the called phone number. 5 | 6 | # 2. Visual Design # 7 | 8 | ![An example of this component](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/lastcall-example.png) 9 | 10 | 11 | # 4. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | lastNumber | "567-242-4774" | This prop is passed into the component. This prop is the last phone number or extension called using the communicator. | 20 | | compStyle | compStyle={}| compStyle is an object that defines styles for the compStyle component. | 21 | | labelText | "No Call" | This prop is passed into the component. This prop provides the text that is place before the lastNumber. | 22 | | cbClick | cbClick={()=>{}} | This prop is a callback function. | 23 | 24 | 25 | ## b. Component State ## 26 | 27 | This component will maintain it's own state for presentational purposes. 28 | 29 | ## c .Component Events ## 30 | 31 | Event | Action(s) 32 | ------------ | ------------- 33 | The last call container is clicked. | This button invokes the callback function lastNumber prop in the component. 34 | 35 | ## d. Context-Aware Specification ## 36 | 37 | This component is NOT a context-aware component 38 | 39 | # 5. Reference Components # 40 | 41 | - VertoBaseComponent 42 | 43 | # 6. Unit Testing Requirement # 44 | 45 | Tests can be found in src/tests 46 | -------------------------------------------------------------------------------- /src/tests/settingsMenuSelect-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import SettingsMenuSelect from '../components/settingsMenuSelect.js'; 6 | 7 | jest.unmock('../components/settingsMenuSelect.js'); 8 | 9 | describe('settingsMenuSelect Component', ()=>{ 10 | 11 | const options=[{id:"none", label:"No Camera"}, {id: "1234", label:"FaceTime HD Camera"}]; 12 | const label="Camera:"; 13 | const selectedOption={id:"selectedVideo", label:"FaceTime HD Camera"}; 14 | const cbSubmitSetting=()=>{console.log('called');}; 15 | 16 | it('renders one select tag', () => { 17 | //expect(true).toBe(true); 18 | const wrapper = shallow( 19 | ); 25 | expect(wrapper.find('select').length).toEqual(1); 26 | }); 27 | 28 | it('renders two options', () => { 29 | //expect(true).toBe(true); 30 | const wrapper = shallow( 31 | ); expect(wrapper.find('option').length).toEqual(2); 37 | }); 38 | 39 | it('cbSubmitSetting callback fires', function () { 40 | const wrapper = shallow( 41 | ); 47 | expect(cbSubmitSetting.calledOnce); 48 | }); 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /src/js/callHistoryService.js: -------------------------------------------------------------------------------- 1 | let _instance; 2 | 3 | class CallHistoryService { 4 | constructor(){ 5 | let lsHistory; 6 | if (localStorage) { 7 | lsHistory = JSON.parse(localStorage.getItem('history')); 8 | } 9 | this.history = { ...lsHistory }; 10 | } 11 | 12 | add(objCallHistory){ 13 | //console.log('CHS: add', objCallHistory); 14 | if (!this.history[objCallHistory.callerId]){ 15 | this.history[objCallHistory.callerId] = []; 16 | } 17 | this.history[objCallHistory.callerId] = [].concat(objCallHistory, this.history[objCallHistory.callerId]); 18 | if (localStorage) { 19 | localStorage.setItem('history', JSON.stringify(this.history)); 20 | } 21 | } 22 | clearHistory(){ 23 | console.log('clear method running hopefully'); 24 | this.history = {}; 25 | } 26 | getHistory(){ 27 | // converting object to array and sorting descending on lasttimestamp 28 | return Object.keys(this.history).map((callerId)=>{ 29 | return { 30 | callerId: callerId, 31 | lastDirection: this.history[callerId][0].direction, 32 | lastTimestamp: this.history[callerId][0].timestamp, 33 | nbrCalls: this.history[callerId].length 34 | }; 35 | }).sort((a,b)=>{ 36 | return a.lastTimestamp < b.lastTimestamp; 37 | }); 38 | } 39 | 40 | getHistoryDetail(callerId){ 41 | // return a new array 42 | if(callerId && this.history[callerId]){ 43 | return [ ...this.history[callerId]]; 44 | } else { 45 | return []; 46 | } 47 | } 48 | 49 | static getInstance() { 50 | if (!_instance) { 51 | _instance = new CallHistoryService(); 52 | } 53 | 54 | return _instance; 55 | } 56 | 57 | } 58 | 59 | //exporting 60 | export default CallHistoryService; 61 | -------------------------------------------------------------------------------- /documents/vcstatus-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: vcstatus # 2 | # 1. Functional Description # 3 | 4 | This component displays a status icon. The icon visually represents the status of the communicator, 5 | 6 | 7 | # 2. Visual Design # 8 | 9 | ![Component's output on the light theme when connecting](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/Status-Icon.png) 10 | 11 | 12 | ![Component's output on the default theme when connecting](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/vcstatus-conencting.png) 13 | 14 | ![Component's output on the default theme when disconnected](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/vcstatus-disconnected.png) 15 | 16 | # 3. Component Type # 17 | 18 | This component will be a 'pure' component. 19 | 20 | ## a. Required Props ## 21 | | prop Name | sample | description | 22 | | ------------ | ------------- | ------------ | 23 | |status | "disconnected" | This prop is sent into the component as a string and is required. If this prop has a value of 'disconnected', 'connected', or 'connecting' the color of the status icon will change accordingly. If a a value other than those listed the component will use the color for disconnected. | 24 | | compStyle | compStyle = {} | This prop is an object and is not required. This object sets the height and width of the SVG status icon.| 25 | 26 | 27 | ## b. Component State ## 28 | 29 | This is a 'pure' component. 30 | 31 | ## c. Context-Aware Specification ## 32 | 33 | This component is a 'pure component'. 34 | 35 | # 4. Reference Components # 36 | 37 | * vertobase component 38 | * svgicons component 39 | 40 | 41 | # 5. Unit Testing Requirement # 42 | 43 | Tests can be found in src/tests. 44 | -------------------------------------------------------------------------------- /documents/input-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Input # 2 | # 1. Functional Description # 3 | 4 | The Input component is an area that displays a label and an input area. 5 | 6 | # 2. Visual Design # 7 | 8 | ![Input Component](./img/input.png) 9 | 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a pure component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | placeHolderTxt | "Send a message..." | _Include a brief description of what the prop does as well as whether it is required or not and its' type_ | 20 | | styles | _NOTE styles are in JSX, not CSX_ { inputWrapStyle: {backgroundColor: '#ddd'} inputStyle {fontSize: '1rem'} }m | Sample: | 21 | | cbSubmit | _Function implemented and bound to a higher-order parent container of this component_ | This prop is a string and is required. This prop is passed into this component from the session component and controls what message we display to the user. | 22 | 23 | ## b. Component State ## 24 | 25 | This component will maintain its own state for presentational purposes. 26 | 27 | Initial state: 28 | this.state = {'onFocus' : false} // menu is initially 'up' 29 | 30 | ## c .Component Events ## 31 | 32 | |Event | Action(s)| 33 | |------------ | -------------| 34 | |Input onFocus | 1 . callback function invoked
    2. change state of onFocus to true| 35 | |Input onBlur | 1. callback function invoked
    2. change state of onFocus to false| 36 | 37 | 38 | ## d. Context-Aware Specification ## 39 | 40 | This component is NOT a context-aware component. 41 | 42 | # 4. Reference Components # 43 | 44 | - VertoBaseComponent 45 | - react-intl 46 | 47 | # 5. Unit Testing Requirement # 48 | 49 | - It displays a label 50 | - It displays an input field. 51 | -------------------------------------------------------------------------------- /documents/callhistoryitem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: CallHistoryItem # 2 | # 1. Functional Description # 3 | 4 | The CallHistoryItem component displays specific information about previously made calls. 5 | 6 | # 2. Visual Design # 7 | 8 | ![CallHistoryItem Component](./img/chi.png) 9 | 10 | # 4. Component Type # 11 | 12 | The CallHistoryItem component will be a pure component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | data | data={} | A required object necessary for displaying call information. | 19 | | compStyle | _NOTE styles are in JSX, not CSS { inputWrapStyle: {backgroundColor: '#ddd'} inputStyle {fontSize: '1rem'} }m | An optional object that customizes style. | 20 | 21 | 22 | ## b. Component State ## 23 | 24 | This component will maintain it's own state for presentational purposes. 25 | 26 | ## c .Component Events ## 27 | 28 | Event | Action(s) 29 | ------------ | ------------- 30 | CallHistoryItem Clicked | 1 .Invoke the callback function with the current key of the component as an argument.
    31 | Hamburger Menu Icon Clicked | 1 .Invoke the callback function with the current key of the component as an argument.
    32 | 33 | ## d. Context-Aware Specification ## 34 | 35 | This component is NOT a context-aware component. 36 | 37 | # 5. Reference Components # 38 | 39 | - VertoBaseComponent 40 | - Radium 41 | - InjectIntl 42 | - svgIcons 43 | 44 | # 6. Unit Testing Requirement # 45 | 46 | - renders a list of of data objects 47 | - renders a callerId in a span 48 | - renders a lastTimestamp in a span 49 | - renders nbrCalls in a span 50 | - renders lastDirection in a span 51 | - dials phone number if component is clicked. 52 | - renders a list of timestamps if hamburger icon is clicked. 53 | -------------------------------------------------------------------------------- /documents/userMenu-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: UserMenu # 2 | # 1. Functional Description # 3 | 4 | The UserMenu component displays a user icon. When clicked, the user icon displays a menu containing a list of actions. When the actions are clicked, they carry out a specific task. 5 | 6 | # 2. Visual Design # 7 | 8 | ![UserMenu Icon](img/um-icon.png)

    9 | ![UserMenu Menu](img/um-menu.png) 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | compStyle | _NOTE styles are in JSX, not CSX_
    { inputWrapStyle:
    {backgroundColor: '#ddd'}
    inputStyle {fontSize: '1rem'}
    } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 20 | 21 | 22 | ## b. Component State ## 23 | 24 | This component will maintain it's own state for dropdownDisplayed. 25 | 26 | ## c .Component Events ## 27 | 28 | If the component needs to react to events (clicks, key presses, etc.) then those events should be listed here along with the action that should be taken: 29 | 30 | Sample: 31 | 32 | | Event | Action(s) | 33 | | ------------ | ------------- | 34 | | userMenu icon clicked | 1 . dropdownDisplayed state is toggled.| 35 | 36 | ## d. Context-Aware Specification ## 37 | 38 | This component is a pure component and it will maintain it’s own state for presentational purposes. 39 | 40 | # 4. Reference Components # 41 | 42 | The component to be developed requires the following components: 43 | 44 | - VertoBaseComponent 45 | - svgIcons 46 | - react-intl 47 | 48 | # 5. Unit Testing Requirement # 49 | 50 | Tests for this component are located at: 51 | 52 | src/tests/userMenu-test.js 53 | -------------------------------------------------------------------------------- /documents/checkbox-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Checkbox # 2 | 3 | # 1. Functional Description # 4 | 5 | The Checkbox component displays either an empty box or a box with a checkmark. 6 | 7 | # 3. Visual Design # 8 | 9 | Currently not available. 10 | 11 | # 4. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | compStyle | compStyle={} | compStyle is an optional prop that allows user to override default styles. | 20 | | defaultCheck | defaultCheck=false | defaultCheck is an optional prop. If true, the component will render a checkbox with a check inside on load. If false, it will render an empty box. By default, it is set to false | 21 | 22 | ## b. Component State ## 23 | 24 | This component will maintain it's own state for presentational purposes 25 | 26 | ## c .Component Events ## 27 | 28 | Event | Action(s) 29 | ------------ | ------------- 30 | Enter/Return key pressed | 1 .Invoke the callback function cbSubmit() with the current value of the input control as an argument.
    2. Clear the input control so that placeholder text is displayed
    3. Keep focus on input control 31 | Clicked | 1. Invoke a callback function. 32 | 33 | 34 | ## d. Context-Aware Specification ## 35 | 36 | This component is NOT a context aware component. 37 | 38 | # 5. Reference Components # 39 | 40 | - React Motion 41 | - svg 42 | - VertoBaseComponent 43 | 44 | 45 | # 6. Unit Testing Requirement # 46 | 47 | - If not clicked width of blank div is 100%. 48 | - If clicked it changes width of blank div to zero. 49 | - If defaultChecked true blank div is 0%. 50 | - If defaultChecked is true and is clicked width of blank div is 100% 51 | - It fires a callback function. 52 | -------------------------------------------------------------------------------- /documents/alertLog-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: AlertLog # 2 | # 1. Functional Description # 3 | 4 | The AlertLog component is a modal displaying AlertLogItem components. The alerts can be cleared from the log by clicking on the **Clear Alerts** button. 5 | 6 | # 2. Visual Design # 7 | 8 | - Alert Log with Alerts: 9 | ![Alert Log Showing Alerts](img/alertLog-full.png) 10 | 11 | - Alert Log with No Alerts: 12 | ![Alert Log Showing No Alerts](img/alertLog-noData.png) 13 | 14 | # 3. Component Type # 15 | 16 | This is a ‘pure' component. 17 | 18 | ## a. Required Props ## 19 | 20 | | Prop Name | Sample | Description | 21 | | ------------ | ------------- | ------------- | 22 | |compStyle | _NOTE styles are in JSX, not CSS_ { alertItemStyles : {display: 'flex',border: '1px solid #d1d1d1', backgroundColor: '#FFF'} } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 23 | 24 | ## b. Component State ## 25 | 26 | ## c .Component Events ## 27 | 28 | | Event | Action(s) | 29 | | ------------ | ------------- | 30 | | 'Clear Alerts' button clicked | 1. Callback function invoked.
    2. State Change.
    3. All alerts are cleared from log. 'No Log Data' modal rendered. | 31 | | 'RemoveIconSVG' clicked | 1. Callback function invoked.
    2. State Change.
    3. Specific alert is removed from alertArray. | 32 | 33 | ## d. Context-Aware Specification ## 34 | 35 | This component is a pure component and it will maintain it’s own state. 36 | 37 | # 4. Reference Components # 38 | 39 | The component to be developed requires the following components: 40 | 41 | - VertoBaseComponent 42 | - ReactIntl 43 | - AlertService 44 | - AlertLogItem 45 | - Modal 46 | 47 | # 5. Unit Testing Requirement # 48 | Tests for this component are located at: 49 | 50 | src/tests/alertLog-test.js 51 | -------------------------------------------------------------------------------- /documents/chatinput-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: chatinput # 2 | 3 | # 1. Functional Description # 4 | 5 | This component is placed at the bottom of the chat area. This component gives each user in a call the ability to type out a message. When the enter button is pressed the message will be put into the chat. 6 | 7 | # 2. Visual Design # 8 | 9 | ![An exanple of a chat message, taken from the 'original' verto ](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/chatmessageitem-img.png) 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | 18 | | Prop Name | Sample | Description | 19 | | ------------ | ------------- | ------------- | 20 | | sessionId | "007" | This prop is string and is not required. This string helps differentiate between different chat sessions. | 21 | | compStyles | compStyle={} | This prop styles the chatinput component. | 22 | | cbSubmitMessage | cbSubmitMessage={()=>{}} | This prop is a function and is not required. This function is a callback to the submit message function. | 23 | 24 | ## b. Component State ## 25 | 26 | This component will maintain it's own state for presentational purposes. 27 | 28 | ## c .Component Events ## 29 | 30 | | Event | Action(s) | 31 | | ------------ | ------------- | 32 | | Enter/Return key pressed | 1 .Invoke the callback function cbSubmitMessage() with the current value of the input control as an argument. 2. Clear the input control so that placeholder text is displayed 3. Keep focus on input control | 33 | 34 | 35 | ## d. Context-Aware Specification ## 36 | 37 | This component is NOT a context-aware component 38 | 39 | # 5. Reference Components # 40 | 41 | - vertobase 42 | 43 | # 6. Unit Testing Requirement # 44 | 45 | Tests can be found in src/tests. 46 | -------------------------------------------------------------------------------- /src/3rd-party/jquery.json.2.5.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery JSON plugin v2.5.1 | github.com/Krinkle/jquery-json */ 2 | !function($){"use strict";var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},hasOwn=Object.prototype.hasOwnProperty;$.toJSON="object"==typeof JSON&&JSON.stringify?JSON.stringify:function(a){if(null===a)return"null";var b,c,d,e,f=$.type(a);if("undefined"===f)return void 0;if("number"===f||"boolean"===f)return String(a);if("string"===f)return $.quoteString(a);if("function"==typeof a.toJSON)return $.toJSON(a.toJSON());if("date"===f){var g=a.getUTCMonth()+1,h=a.getUTCDate(),i=a.getUTCFullYear(),j=a.getUTCHours(),k=a.getUTCMinutes(),l=a.getUTCSeconds(),m=a.getUTCMilliseconds();return 10>g&&(g="0"+g),10>h&&(h="0"+h),10>j&&(j="0"+j),10>k&&(k="0"+k),10>l&&(l="0"+l),100>m&&(m="0"+m),10>m&&(m="0"+m),'"'+i+"-"+g+"-"+h+"T"+j+":"+k+":"+l+"."+m+'Z"'}if(b=[],$.isArray(a)){for(c=0;c | This prop is a function and is required. | 20 | | compStyle | compStyle={} | compStyle is an object that defines styles for the component. | 21 | | settingsData | settingData={} | This prop is an object and is required. This provides the component with the default settings the user has for their microphone and camera| 22 | 23 | 24 | 25 | ## b. Component State ## 26 | 27 | This component will maintain it's own state for presentational purposes. 28 | 29 | ## c .Component Events ## 30 | 31 | | Event | Action(s) | 32 | | ------------ | ------------- | 33 | | refresh button is clicked | When the refresh button is clicked the callback function refresh() is called. | 34 | | save button is clicked | When the save button is clicked the callback function saveSettings() is called. | 35 | 36 | 37 | ## d. Context-Aware Specification ## 38 | 39 | This component is a pure component and it will maintain it’s own state for presentational purposes. 40 | 41 | # 5. Reference Components # 42 | 43 | - svgIcons
    44 | - VertoBaseComponent
    45 | - ReactIntl 46 | - vMeter 47 | - volumeMeter 48 | - settingsMenuSelect 49 | 50 | # 6. Unit Testing Requirement # 51 | 52 | Tests for this component are located at: 53 | 54 | src/tests/nsindicator-test.js 55 | -------------------------------------------------------------------------------- /src/js/alertService.js: -------------------------------------------------------------------------------- 1 | let _instance; 2 | 3 | class AlertService { 4 | constructor(){ 5 | let lsAlertLog; 6 | if (localStorage) { 7 | lsAlertLog = JSON.parse(localStorage.getItem('alerts')); 8 | } 9 | this.alerts = lsAlertLog; 10 | 11 | } 12 | 13 | createAlert(objAlertItem) { 14 | //console.log('alert: create', objAlertItem);ß 15 | // objAlertItem 16 | // { 17 | // level: info/warn/error 18 | // timestamp: 19 | // summary: brief string that will go in headingStyle 20 | // detail: more information on the alert... 21 | // } 22 | 23 | // initialize if alerts log does not exist 24 | if (!this.alerts){ 25 | this.alerts = []; 26 | } 27 | this.alerts = [].concat(objAlertItem, this.alerts); 28 | if (localStorage) { 29 | localStorage.setItem('alerts', JSON.stringify(this.alerts)); 30 | } 31 | 32 | let event = new CustomEvent('alert', { detail: {alert: objAlertItem}}); 33 | 34 | document.dispatchEvent(event); 35 | } 36 | 37 | clearAlerts(){ 38 | this.alerts = []; 39 | 40 | // clear the local storage 41 | if (localStorage) { 42 | localStorage.setItem('alerts', JSON.stringify(this.alerts)); 43 | } 44 | } 45 | 46 | setAlertLog(alertArray){ 47 | this.alerts = alertArray; 48 | // update the local storage 49 | if (localStorage) { 50 | localStorage.setItem('alerts', JSON.stringify(this.alerts)); 51 | } 52 | } 53 | 54 | getAlertLog(){ 55 | // converting object to array and sorting descending on lasttimestamp 56 | if (this.alerts){ 57 | return this.alerts.sort((a,b)=>{ 58 | return a.timestamp < b.timestamp; 59 | }); 60 | } else { 61 | return []; 62 | } 63 | 64 | } 65 | 66 | static getInstance() { 67 | if (!_instance) { 68 | _instance = new AlertService(); 69 | } 70 | 71 | return _instance; 72 | } 73 | 74 | } 75 | 76 | //exporting 77 | export default AlertService; 78 | -------------------------------------------------------------------------------- /src/components/contributorsListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | compStyle: React.PropTypes.object, 6 | name: React.PropTypes.string.isRequired, 7 | email: React.PropTypes.string.isRequired, 8 | avatar: React.PropTypes.string.isRequired 9 | }; 10 | 11 | class ContributorsList extends VertoBaseComponent{ 12 | 13 | constructor(props) { 14 | super(props); 15 | } 16 | 17 | 18 | getDefaultStyle(styleName) { 19 | const styles = { 20 | 21 | totalStyle: { 22 | display: "flex", 23 | alignItems: "center", 24 | justifyContent: "space-around", 25 | flexWrap: "wrap", 26 | marginBottom: '20px' 27 | }, 28 | 29 | imageStyle: { 30 | borderRadius: "50%" 31 | }, 32 | 33 | infoStyle: { 34 | display: "flex", 35 | flexDirection: "column", 36 | justifyContent: "flex-start", 37 | width: "50%", 38 | wordWrap: 'break-word', 39 | minWidth: '165px' 40 | }, 41 | 42 | nameStyle: { 43 | fontSize: 20, 44 | paddingBottom: "5px" 45 | } 46 | }; 47 | return (styles[styleName]); 48 | } 49 | 50 | render() { 51 | return ( 52 |
    53 | 54 | 55 | 56 | 57 | 58 | {this.props.name}
    59 |
    60 | {this.props.email} 61 |
    62 |
    63 | ); 64 | } 65 | } 66 | 67 | ContributorsList.propTypes = propTypes; 68 | 69 | export default ContributorsList; 70 | // reviewed 7/13/2016 71 | -------------------------------------------------------------------------------- /src/tests/alertLog-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | // import AlertService from '../js/alertService'; 7 | import AlertLog from '../components/alertLog'; 8 | import AlertLogItem from '../components/alertLogItem'; 9 | 10 | jest.unmock('../js/alertService'); 11 | jest.unmock('../components/alertLog'); 12 | jest.unmock('../components/alertLogItem'); 13 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 14 | 15 | describe('Default test for AlertLog', ()=>{ 16 | 17 | function storageMock() { 18 | var storage = {}; 19 | 20 | return { 21 | setItem: function(key, value) { 22 | storage[key] = value || ''; 23 | }, 24 | getItem: function(key) { 25 | return storage[key] || null; 26 | }, 27 | removeItem: function(key) { 28 | delete storage[key]; 29 | }, 30 | get length() { 31 | return Object.keys(storage).length; 32 | }, 33 | key: function(i) { 34 | var keys = Object.keys(storage); 35 | return keys[i] || null; 36 | } 37 | }; 38 | } 39 | 40 | window.localStorage = storageMock(); 41 | 42 | const cbRemoveAlert = sinon.spy(); 43 | 44 | const sampleData = { 45 | level:"warn", 46 | timestamp:1466703201123, 47 | summary: "Can't hang up while sharing screen", 48 | detail: "You must stop sharing your screen before you can hangup the call", 49 | id: 0 50 | }; 51 | const sampleKey = { 52 | id: 0 53 | }; 54 | 55 | 56 | it('renders a modal', () => { 57 | const wrapper = shallowWithIntl(); 58 | expect(wrapper.find('Modal').length).toEqual(1); 59 | }); 60 | 61 | it('renders two divs', () => { 62 | const wrapper = shallow(); 63 | 64 | expect(wrapper.find('div').length).toEqual(1); 65 | }); 66 | 67 | }); 68 | -------------------------------------------------------------------------------- /src/components/controlItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import * as icons from './svgIcons'; 4 | 5 | const propTypes = { 6 | cbActionClick : React.PropTypes.func, 7 | description : React.PropTypes.string, 8 | compStyle : React.PropTypes.object, 9 | label : React.PropTypes.string, 10 | type : React.PropTypes.string 11 | }; 12 | const defaultProps = { 13 | compStyle : {svgStyle:{fill: '#6b6c6c', height: '24px', width: '24px'}} 14 | }; 15 | 16 | class ControlItem extends VertoBaseComponent { 17 | constructor(props){ 18 | super(props); 19 | } 20 | 21 | 22 | getDefaultStyle(styleName) { 23 | const styles = { 24 | controlStyle: { 25 | cursor: 'pointer', 26 | fontSize: '1rem', 27 | display: 'flex', 28 | flexDirection: 'column', 29 | alignItems: 'center' 30 | }, 31 | svgStyle: { 32 | height: '20px', 33 | fill: '#65ac43' 34 | } 35 | }; 36 | 37 | return styles[styleName]; 38 | } 39 | 40 | render(){ 41 | //variable must begin with capital letter or will NOT render. 42 | let DynamicIcon; 43 | if(icons.hasOwnProperty(this.props.type)){ 44 | DynamicIcon = icons[this.props.type]; 45 | } 46 | // console.log('---->',DynamicIcon); 47 | return ( 48 | { 50 | if (this.props.cbActionClick) { 51 | this.props.cbActionClick(); 52 | } 53 | }} 54 | > 55 | 58 | 59 | {this.props.label} 60 | 61 | 62 | ); 63 | } 64 | } 65 | 66 | ControlItem.propTypes = propTypes; 67 | ControlItem.defaultProps = defaultProps; 68 | 69 | export default ControlItem; 70 | // reviewed 7/13/2016 71 | -------------------------------------------------------------------------------- /documents/settings-checkbox-spec.md: -------------------------------------------------------------------------------- 1 | e# Component Name: SettingsCheckbox # 2 | # 1. Functional Description # 3 | 4 | SettingsCheckbox is a simple checkbox component used in the Settings component. 5 | 6 | # 2. Visual Design # 7 | 8 | - Settings Checkbox (checked): 9 | ![Settings Checkbox(checked)](img/settings-cbox-checked.png) 10 | 11 | - Settings Checkbox (unchecked): 12 | ![Settings Checkbox(unchecked)](img/settings-cbox-unchecked.png) 13 | 14 | # 3. Component Type # 15 | 16 | This is a ‘pure' component. 17 | 18 | ## a. Required Props ## 19 | 20 | | Prop Name | Sample | Description | 21 | | ------------ | ------------- | ------------- | 22 | | checkedOption:
    name: React.PropTypes.string, value: React.PropTypes.bool |checkedOption={name:"useVideo", value:this.props.settings.useVideo} | An object. Required. Contains the data for a setting checkbox field. 23 | | compStyle | _NOTE styles are in JSX, not CSX_ { container: {display: 'flex', position: 'relative'}, inputStyle {fontSize: '1rem'} } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 24 | | cbSubmitSetting | Function implemented and bound to a higher-order parent container of this component | Function. Required. This prop is invoked when a setting is changed by either selecting a menu item or checking a box. | 25 | 26 | 27 | ## b. Component State ## 28 | This component will maintain it's own state for checkStatus. 29 | 30 | ## c .Component Events ## 31 | 32 | | Event | Action(s) | 33 | | ------------ | ------------- | 34 | | onChange | call cbSubmitSetting() | 35 | 36 | ## d. Context-Aware Specification ## 37 | 38 | This component is a pure component and it will maintain it’s own state. 39 | 40 | # 4. Reference Components # 41 | 42 | The component to be developed requires the following components: 43 | 44 | - VertoBaseComponent 45 | - svgIcons 46 | 47 | # 5. Unit Testing Requirement # 48 | Tests for this component are located at: 49 | 50 | src/tests/settingsMenuCheckbox-test.js 51 | -------------------------------------------------------------------------------- /src/tests/contributorlistitem-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import ContributorsListItem from '../components/contributorsListItem'; 7 | 8 | jest.unmock('../components/contributorsListItem'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | 12 | describe('Default test for contributorsListItem', ()=>{ 13 | 14 | 15 | it('the name prop gets passed in properly to the component', () => { 16 | const wrapper = mountWithIntl({}}/>); 17 | expect(wrapper.props().name).toEqual('Matt'); 18 | }); 19 | 20 | it('the email prop gets passed in properly to the component', () => { 21 | const wrapper = mountWithIntl({}}/>); 22 | expect(wrapper.props().email).toEqual('Matt@matt.com'); 23 | }); 24 | 25 | it('the avatar prop gets passed in properly to the component', () => { 26 | const wrapper = mountWithIntl({}}/>); 27 | expect(wrapper.props().avatar).toEqual('../../pic.png'); 28 | }); 29 | 30 | it('renders the correct number of statements based on the number of divs and spans', () => { 31 | const wrapper = mountWithIntl({}}/>); 32 | expect(wrapper.find('div' && 'span').length).toEqual(3); 33 | }); 34 | 35 | it('renders one user icon per run', () => { 36 | const wrapper = mountWithIntl({}}/>); 37 | expect(wrapper.find('img').length).toEqual(1); 38 | }); 39 | 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /documents/nsindicator-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: network-status-indicator 2 | # 1. Functional Description # 3 | 4 | The NetworkStatusIndicator component displays a network status icon. It can be clicked to display specific network information. 5 | 6 | # 2. Visual Design # 7 | 8 | ![network-status-indicator icon](img/nsi-icon.png)

    9 | ![network-status-indicator menu](img/nsi-menu.png) 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | |------------ | ------------- | ---------------| 19 | |networkData | networkData={
    upkpbs: {value},
    downkpbs: {value},
    videoResolution: {value}
    } | Required. An object that contains properties necessary for calculating the correct icon to render and content to display. | 20 | |addMenuOption | addMenuOption={}| An optional object that may contain a method to run onClick| 21 | |compStyle | compStyle={} | An object that contains css styles.| 22 | | allowDisplayDetails | allowDisplayDetails={true} | A boolean. If true, it will render the caret icon and a dropdown menu. If false, it will simply render the network-status icon| 23 | 24 | ## b. Component State ## 25 | 26 | This component will maintain it's own state for dropdownDisplayed. 27 | 28 | ## c. Component Events ## 29 | 30 | |Event | Action(s)| 31 | |------------ | -------------| 32 | |network-status-indicator icon clicked | 1 . dropdownDisplayed state is toggled.| 33 | |NetworkStatusIndicator.toggleDisplay() called | 1. dropdownDisplayed state is toggled | 34 | 35 | 36 | 37 | ## d. Context-Aware Specification ## 38 | 39 | This component is a pure component and it will maintain it’s own state for presentational purposes. 40 | 41 | # 5. Reference Components # 42 | 43 | The component to be developed requires the following components: 44 | 45 | - svgIcons
    46 | - VertoBaseComponent
    47 | - ReactIntl
    48 | 49 | 50 | # 6. Unit Testing Requirement # 51 | 52 | Tests for this component are located at: 53 | 54 | src/tests/nsindicator-test.js 55 | -------------------------------------------------------------------------------- /documents/memberItem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: MemberItem # 2 | # 1. Functional Description # 3 | 4 | This component creates the member item for a video session. It is a rectangular display showing user avatar, name, email, and 2 icons (microphone & video). The icons are clicked to mute/unmute audio and/or video. Badges will appear across the bottom to indicate when the user has the Floor, when the Floor is locked, when Screen Share is enabled, and Presenter Status. 5 | 6 | # 2. Visual Design # 7 | 8 | ![A visual example of MemberList](img/memberItem-img.png) 9 | 10 | Floor and presenter badges: 11 | ![A visual example of MemberList badges: floor & presenter](img/floor-presenter-badges.png) 12 | 13 | Floor locked badge:
    14 | ![A visual example of MemberList badges:](img/floorlocked-presenter-badges.png) 15 | 16 | # 3. Component Type # 17 | 18 | This component will be a 'pure' component. 19 | 20 | ## a. Required Props ## 21 | 22 | | Prop Name | Sample | Description | 23 | | ------------ | ------------- | ------------- | 24 | | cbControlClick | Function implemented and bound to a higher-order parent container of this component. | Function. Required. This prop is invoked when a control is used by clicking a control icon. | 25 | | controlSettings: moderator: React.PropTypes.bool, multCanvas: React.PropTypes.bool, allowPresenter: React.PropTypes.bool | isModerator={confData.currentRole == "moderator"} allowPresenter={true} hasMultipleCanvases={false} | Object. Required. Contains the data for the control settings. 26 | | member | member={} | Object. Required. Contains all necessary member data. | 27 | 28 | 29 | ## b. Component State ## 30 | 31 | This component will maintain it's own state for presentational purposes. 32 | 33 | ## c. Context-Aware Specification ## 34 | 35 | his component is NOT a context-aware component 36 | 37 | # 5. Reference Components # 38 | 39 | - VertoBaseComponent 40 | - AdminControls 41 | - ControlItem 42 | - SvgIcons 43 | 44 | # 6. Unit Testing Requirement # 45 | Tests for this component are located at: 46 | 47 | src/tests/memberItem-test.js 48 | -------------------------------------------------------------------------------- /src/components/volumeMeter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import { MicrophoneIconSVG } from './svgIcons'; 4 | 5 | const propTypes = { 6 | compStyle: React.PropTypes.object, 7 | volumeLevel: React.PropTypes.number.isRequired 8 | }; 9 | 10 | class VolumeMeter extends VertoBaseComponent{ 11 | constructor(props) { 12 | super(props); 13 | } 14 | 15 | 16 | getDefaultStyle(styleName) { 17 | const styles = { 18 | volMeterStyles: { 19 | display: 'flex', 20 | flexDirection: 'column' 21 | }, 22 | segmentOffStyle: { 23 | border: 'solid 1px #ccc', 24 | borderRadius: '6px', 25 | height: '10px', 26 | width: '40px', 27 | marginTop: '5px' 28 | }, 29 | segmentOnStyle: { 30 | border: 'solid 1px #ccc', 31 | borderRadius: '6px', 32 | height: '10px', 33 | width: '40px', 34 | backgroundColor: '#ccc', 35 | marginTop: '5px' 36 | }, 37 | svgMicStyle: { 38 | width: '40px', 39 | height: '40px', 40 | fill: '#ccc' 41 | 42 | } 43 | }; 44 | 45 | return (styles[styleName]); 46 | } 47 | 48 | render() { 49 | let volSegArray = [5,4,3,2,1]; 50 | volSegArray = volSegArray.map((segment)=>{ 51 | if (this.props.volumeLevel > (segment-1) * 20 +1) { 52 | return ( 53 |
    54 | ); 55 | } else { 56 | return ( 57 |
    58 | ); 59 | } 60 | }); 61 | return ( 62 |
    63 | {volSegArray} 64 | 65 |
    66 | 67 | ); 68 | } 69 | } 70 | 71 | VolumeMeter.propTypes = propTypes; 72 | 73 | export default VolumeMeter; 74 | // reviewed on 7/15/2016 75 | -------------------------------------------------------------------------------- /documents/settings-menu-select-spec: -------------------------------------------------------------------------------- 1 | # Component Name: SettingsMenuSelect # 2 | # 1. Functional Description # 3 | 4 | SettingsMenuSelect is a simple select menu component used in the Settings component. 5 | 6 | # 2. Visual Design # 7 | 8 | - Settings Menu Select Default: 9 | ![Settings Component Full](img/settings-menuSelect-default.png) 10 | 11 | - Settings Menu Select Open: 12 | ![Settings Component Full](img/settings-menuSelect-open.png) 13 | 14 | # 3. Component Type # 15 | 16 | This is a ‘pure' component. 17 | 18 | ## a. Required Props ## 19 | 20 | | Prop Name | Sample | Description | 21 | | ------------ | ------------- | ------------- | 22 | | selectedOption | selectedOption={id:"selectedVideo", label:"FaceTime HD Camera"} | An object. Required. Contains the selected data for a setting select field. 23 | | compStyle | _NOTE styles are in JSX, not CSX_ { container: {display: 'flex', position: 'relative'}, inputStyle {fontSize: '1rem'} }m | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 24 | | cbSubmitSetting | Function implemented and bound to a higher-order parent container of this component | Function. Required. This prop is invoked when a setting is changed by either selecting a menu item or checking a box. | 25 | | options | options =[{id:"none", label:"No Camera"}, {id: "...", label:"FaceTime HD Camera"}] | Array.Required. Array of options for select menu.| 26 | | label | "Camera:" | String. Required. Label for select menu. 27 | 28 | ## b. Component State ## 29 | 30 | ## c .Component Events ## 31 | 32 | | Event | Action(s) | 33 | | ------------ | ------------- | 34 | | onChange | call cbSubmitSetting() | 35 | 36 | ## d. Context-Aware Specification ## 37 | 38 | This component is a pure component and it will maintain it’s own state. 39 | 40 | # 4. Reference Components # 41 | 42 | The component to be developed requires the following components: 43 | 44 | - vertobasecomponent 45 | 46 | # 5. Unit Testing Requirement # 47 | Tests for this component are located at: 48 | 49 | src/tests/settingsMenuSelect-test.js 50 | -------------------------------------------------------------------------------- /src/components/lastCall.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ToolTip from './tooltip'; 4 | import { injectIntl } from 'react-intl' 5 | 6 | const propTypes = { 7 | lastNumber: React.PropTypes.string, 8 | labelText: React.PropTypes.string, 9 | cbClick: React.PropTypes.func, 10 | compStyle: React.PropTypes.object, 11 | ttPosition: React.PropTypes.string 12 | }; 13 | 14 | class LastCall extends VertoBaseComponent { 15 | constructor(props) { 16 | super(props); 17 | this.call = this.call.bind(this); 18 | } 19 | 20 | 21 | 22 | getDefaultStyle(styleName) { 23 | const styles = { 24 | lastCallStyle: { 25 | paddingLeft: '10px', 26 | paddingRight: '20px' 27 | }, 28 | container: { 29 | cursor: (this.props.cbClick ? 'pointer':'auto') 30 | } 31 | }; 32 | return (styles[styleName]); 33 | } 34 | 35 | call() { 36 | if (this.props.cbClick) { 37 | this.props.cbClick(this.props.lastNumber); 38 | } 39 | } 40 | 41 | render() { 42 | const { formatMessage } = this.props.intl; 43 | let theMsg = formatMessage({"id":"CLICK_DIAL", "defaultMessage":"Click to Dial"}); 44 | let lastcall = (
    45 | 46 | {this.props.labelText}{this.props.lastNumber ? this.props.lastNumber :''} 47 | 48 |
    ); 49 | 50 | 51 | if(this.props.labelText !== "No Call" && this.props.labelText !== "In Call: "){ 52 | lastcall = {lastcall}; 53 | } 54 | //console.log("^^^^^^^^^^^^^^^^^^^^^^^^^", lastcalll); 55 | return ( 56 | lastcall 57 | ); 58 | } 59 | } 60 | 61 | LastCall.propTypes = propTypes; 62 | 63 | export default injectIntl(LastCall); 64 | // reviewed on 7/13/2016 65 | -------------------------------------------------------------------------------- /documents/alertLogItem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: AlertLogItem # 2 | # 1. Functional Description # 3 | 4 | AlertLogItem is a simple list item component used in the AlertLog component. Based on the level, the alert tab will change color: "error" = red (*#FD5F56*), "warn" = yellow (*#FFC02F*) as shown, & "info" = green *(#63B653*) 5 | 6 | # 2. Visual Design # 7 | 8 | - Alert Log Item: 9 | ![Alert Log Item Pic](img/alertLogItem.png) 10 | 11 | # 3. Component Type # 12 | 13 | This is a ‘pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | alertData | alertData={level:"warn", timestamp:1466703201123, summary: "Can't hang up while sharing screen",
    detail: "You must stop sharing your screen before you can hangup the call",
    id: 0} | An object. Required. Contains the data for alerts.| 20 | | cbRemoveAlert | Function implemented and bound to a higher-order parent container of this component | Function. Required. This prop is invoked when clicking the RemoveIconSVG to remove an alert from log. | 21 | |compStyle | _NOTE styles are in JSX, not CSS_ { alertItemStyles : {display: 'flex',border: '1px solid #d1d1d1', backgroundColor: '#FFF'} } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 22 | | index | index: 0 | Number. Indexes each alertItem. 23 | 24 | ## b. Component State ## 25 | 26 | ## c .Component Events ## 27 | 28 | | Event | Action(s) | 29 | | ------------ | ------------- | 30 | | 'RemoveIconSVG' clicked | 1. Callback function invoked.
    2. State Change.
    3. Specific alert is removed from alertLog. | 31 | 32 | ## d. Context-Aware Specification ## 33 | 34 | This component is a pure component and it will maintain it’s own state. 35 | 36 | # 4. Reference Components # 37 | 38 | The component to be developed requires the following components: 39 | 40 | - VertoBaseComponent 41 | - ControlItem 42 | - moment 43 | 44 | # 5. Unit Testing Requirement # 45 | Tests for this component are located at: 46 | 47 | src/tests/alertLogItem-test.js 48 | -------------------------------------------------------------------------------- /src/tests/aboutComp-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import About from '../components/about'; 7 | 8 | jest.unmock('../components/about.js'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | //the three tests that fail are the result of the fact that the gitRev section of the component was removed recently 12 | 13 | describe('Default test for about', ()=>{ 14 | 15 | it('renders the correct number of elements', () => { 16 | const wrapper = shallowWithIntl({}}/>); 17 | expect(wrapper.find('div').length).toEqual(5); 18 | }); 19 | 20 | it('assigns the correct value to version, depending on what is passed in', () => { 21 | const wrapper = mountWithIntl({}}/>); 22 | expect(wrapper.props().version).toEqual('3.9.236'); 23 | }); 24 | 25 | it('assigns the correct value to gitRev, depending on what is passed in', () => { 26 | const wrapper = mountWithIntl({}}/>); 27 | expect(wrapper.props().gitRev).toEqual('LRE785'); 28 | }); 29 | 30 | it('renders the images', () => { 31 | const wrapper = shallowWithIntl({}}/>); 32 | expect(wrapper.find('img').length).toEqual(2); 33 | }); 34 | 35 | it('renders a modal', () => { 36 | const wrapper = shallowWithIntl({}}/>); 37 | expect(wrapper.find('Modal').length).toEqual(1); 38 | }); 39 | 40 | it('the component has 3 internationalized messages', () => { 41 | const wrapper = shallowWithIntl({}}/>); 42 | expect(wrapper.find('FormattedMessage').length).toEqual(3); 43 | }); 44 | 45 | it('prints the gitRev and version props in line with their FormattedMessages', () => { 46 | const wrapper = shallowWithIntl({}}/>); 47 | expect(wrapper.find('span').length).toEqual(2); 48 | }); 49 | 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | 5 | var config = { 6 | entry: { 7 | app: path.resolve(__dirname, './src/main.js'), 8 | vendors: ['react','react-dom'] 9 | }, 10 | output: { 11 | path: './src', 12 | filename: 'bundle.js' 13 | }, 14 | devServer: { 15 | inline: true, 16 | contentBase: './src', 17 | port: 8080 18 | }, 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | exclude: /node_modules/, 24 | loaders: ["react-hot", "babel?presets[]=es2015&presets[]=stage-0&presets[]=react"] 25 | } 26 | ] 27 | }, 28 | plugins: [ 29 | new webpack.optimize.OccurenceOrderPlugin(true), 30 | new webpack.optimize.DedupePlugin(), 31 | new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js') 32 | ] 33 | } 34 | console.log('---> ', process.env.NODE_ENV ); 35 | //export NODE_ENV=production 36 | // unset NODE_ENV 37 | if (process.env.NODE_ENV === 'production') { 38 | config.output.path = path.join(__dirname, 'dist/') 39 | config.plugins.push(new webpack.optimize.UglifyJsPlugin({ 40 | output: { 41 | comments: false 42 | }, 43 | compress: { 44 | warnings: false, 45 | screw_ie8: true 46 | } 47 | })); 48 | config.plugins.push(new webpack.DefinePlugin({ 49 | 'process.env': { 50 | 'NODE_ENV': '"production"' 51 | } 52 | })); 53 | config.plugins.push(new CopyWebpackPlugin([ 54 | // {output}/file.txt 55 | //{ from: 'messages', to: 'messages' }, 56 | { from: 'src/index.html', to: 'index.html' }, 57 | { from: 'src/css', to: 'css'}, 58 | { from: 'src/img', to: 'img' }, 59 | { from: 'images', to: 'img' }, 60 | { from: 'src/locales', to: 'locales'}, 61 | { from: 'src/3rd-party', to: '3rd-party'}, 62 | { from: 'src/favicon.ico', to: 'favicon.ico' } 63 | ], { 64 | ignore: [ 65 | // Doesn't copy any files with a txt extension 66 | '*.txt' 67 | ] 68 | })); 69 | } 70 | 71 | module.exports = config 72 | -------------------------------------------------------------------------------- /src/tests/nsindicator-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 7 | import NetworkStatusIndicator from '../components/nsIndicator.js'; 8 | 9 | jest.unmock('../components/nsIndicator.js'); 10 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 11 | jest.unmock('../js/messages.js'); 12 | 13 | 14 | describe('', ()=>{ 15 | 16 | const sampleData = { 17 | upkpbs : 5000, 18 | downkpbs : 5000, 19 | vidQual : 'Swell' 20 | }; 21 | 22 | const medData = { 23 | upkpbs : 2001, 24 | downkpbs : 1999, 25 | vidQual : 'Splendid' 26 | }; 27 | 28 | const lowData = { 29 | upkpbs : 1999, 30 | downkpbs: 1999, 31 | vidQual : 'so fresh' 32 | }; 33 | 34 | const badData = { 35 | fakeData: 'hehehehehehee' 36 | }; 37 | 38 | //works 39 | it('renders allowDisplayDetails as false if provided', () => { 40 | const wrapper = mountWithIntl(); 41 | expect(wrapper.find('NetworkStatusIndicator').length).toEqual(1); 42 | }); 43 | 44 | // Iw 45 | it('renders CaretUpIconSVG if displayDropdown is true', () => { 46 | const wrapper = shallowWithIntl(); 47 | wrapper.setState({ dropdownDisplayed: true}); 48 | expect(wrapper.find('CaretUpIconSVG').length).toEqual(0); 49 | }); 50 | 51 | //w 52 | it('renders CaretUpIconSVG if displayDropdown is true', () => { 53 | const wrapper = shallowWithIntl(); 54 | wrapper.setState({ dropdownDisplayed: false}); 55 | expect(wrapper.find('CaretDownIconSVG').length).toEqual(0); 56 | }); 57 | 58 | it('properly takes in and displays the networkdata', () => { 59 | const wrapper = shallowWithIntl(); 60 | //console.log('>>>>>>>>>', wrapper.node.props.networkData.downkpbs); 61 | expect(wrapper.node.props.networkData.vidQual).toEqual('so fresh'); 62 | }); 63 | 64 | 65 | }); 66 | -------------------------------------------------------------------------------- /src/components/vertobasecomponent.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import themes from '../themes/theme-styles.js'; 3 | 4 | const objectMerge = require('object-merge'); 5 | 6 | class VertoBaseComponent extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | } 10 | findWrappedMethods(obj={},methodName){ 11 | if (!methodName) return; 12 | 13 | if (obj[methodName]) 14 | return obj; 15 | 16 | if(obj['getWrappedInstance']){ 17 | return this.findWrappedMethods(obj['getWrappedInstance'](), methodName); 18 | } 19 | 20 | return; 21 | } 22 | getClassName() { 23 | const xName = Object.getPrototypeOf(this.constructor).name; 24 | // if it equals base we need to just get it from constructor ... we handle higher order objects by default 25 | return xName.toLowerCase() === 'vertobasecomponent' ? this.constructor.name : xName; 26 | } 27 | applyThemeStyle(styleName, styles) { 28 | // NOTE: the 'themes' object is imported (in case you are looking for where 29 | // it is defined) 30 | 31 | const componentName = this.getClassName().toLowerCase(); 32 | if(themes[window.theme.value][componentName] && themes[window.theme.value][componentName][styleName]) { 33 | return( objectMerge( styles, themes[window.theme.value][componentName][styleName])); 34 | } else{ 35 | return( styles ); 36 | } 37 | } 38 | 39 | 40 | getCompStyle(styleName) { 41 | return this.props.compStyle && this.props.compStyle[styleName] ? this.props.compStyle[styleName] : this.props.compStyle ; 42 | } 43 | 44 | getStyle(styleName) { 45 | const styles = this.getDefaultStyle(styleName); 46 | 47 | let styleReturn = styles; 48 | 49 | // apply the themed styling 50 | if(window.theme && (window.theme.value != 'default')) { 51 | styleReturn = this.applyThemeStyle(styleName, styles); 52 | } 53 | 54 | // apply style from props 55 | const compStyle = this.getCompStyle(); 56 | if(compStyle && compStyle[styleName]) { 57 | styleReturn = objectMerge(styleReturn, compStyle[styleName]); 58 | } 59 | return styleReturn; 60 | } 61 | 62 | } 63 | 64 | export default VertoBaseComponent; 65 | // reviewed on 7/14/2016 66 | -------------------------------------------------------------------------------- /src/components/alertList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import AlertItem from './alertItem'; 4 | 5 | const propTypes = { 6 | compStyle : React.PropTypes.object 7 | }; 8 | 9 | class AlertList extends VertoBaseComponent { 10 | constructor(props){ 11 | super(props); 12 | this.state = {alertArray: []}; 13 | this.nextId = 0; 14 | 15 | this.handleNewAlert = this.handleNewAlert.bind(this); 16 | this.handleDismissAlert = this.handleDismissAlert.bind(this); 17 | } 18 | 19 | componentDidMount(){ 20 | document.addEventListener('alert', this.handleNewAlert); 21 | } 22 | 23 | 24 | getDefaultStyle(styleName) { 25 | const styles = { 26 | ALStyles : { 27 | maxHeight: '100%', // need this so list will scroll on overflow... 28 | overflowY: 'auto', 29 | position: 'absolute', 30 | top: '10px', 31 | right: '15px', 32 | width: '30vw', 33 | maxWidth: '300px' 34 | } 35 | }; 36 | 37 | return styles[styleName]; 38 | } 39 | 40 | handleNewAlert(e){ 41 | // add the new alert to start of this.state.alertArray. Use concat!!!! 42 | const newObj = { ...e.detail.alert, id: this.nextId++}; 43 | 44 | this.setState({...this.state, alertArray: [newObj].concat(this.state.alertArray)}); 45 | } 46 | 47 | handleDismissAlert(id) { 48 | // remove the alert at dismissIndex from this.state.alertArray 49 | 50 | let newAlertArray = this.state.alertArray.filter((a)=>{ 51 | return a.id != id; 52 | }); 53 | 54 | this.setState({...this.state, alertArray: newAlertArray}); 55 | } 56 | 57 | render(){ 58 | //console.log('---- ', this.state.alertArray); 59 | 60 | return( 61 |
    62 | {this.state.alertArray.map((a)=>{ 63 | return ( 64 | ); 69 | })} 70 |
    71 | ); 72 | } 73 | } 74 | 75 | AlertList.propTypes = propTypes; 76 | 77 | export default AlertList; 78 | // reviewed 7/13/2016 79 | -------------------------------------------------------------------------------- /documents/alertItem-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: AlertItem # 2 | # 1. Functional Description # 3 | 4 | AlertItem is a simple list item component used in the AlertList component. The alerts will display in AlertList for 5 seconds then timeout or they can be dismissed by clicking the RemoveIconSVG (the 'x' in the top right corner). Based on the level, the alert heading will change color: "error" = red (*#FD5F56*), "warn" = yellow (*#FFC02F*) as shown, & "info" = green *(#63B653*) 5 | 6 | # 2. Visual Design # 7 | 8 | - Alert Item:
    9 | ![Alert Item Image](img/alertItem.png) 10 | 11 | # 3. Component Type # 12 | 13 | This is a ‘pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | alertData | alertData={level:"warn", timestamp:1466703201123, summary: "Can't hang up while sharing screen",
    detail: "You must stop sharing your screen before you can hangup the call",
    id: 0} | An object. Required. Contains the data for alerts.| 20 | | cbDismissAlert | Function implemented and bound to a higher-order parent container of this component | Function. Required. This prop is invoked when clicking the RemoveIconSVG to dismiss an alert, removing from alert list. | 21 | |compStyle | _NOTE styles are in JSX, not CSS_ { alertItemStyles : {display: 'flex',border: '1px solid #d1d1d1', backgroundColor: '#FFF'} } | Optional prop. If value is provided, then it will render new styles, if not it will render default styling. | 22 | | index | index: 0 | Number. Indexes each alertItem. 23 | 24 | ## b. Component State ## 25 | 26 | ## c .Component Events ## 27 | 28 | | Event | Action(s) | 29 | | ------------ | ------------- | 30 | | 'RemoveIconSVG' clicked | 1. Callback function invoked.
    2. State Change.
    3. Specific alert is removed from alertList. | 31 | 32 | ## d. Context-Aware Specification ## 33 | 34 | This component is a pure component and it will maintain it’s own state. 35 | 36 | # 4. Reference Components # 37 | 38 | The component to be developed requires the following components: 39 | 40 | - VertoBaseComponent 41 | - ControlItem 42 | 43 | # 5. Unit Testing Requirement # 44 | Tests for this component are located at: 45 | 46 | src/tests/alertItem-test.js 47 | -------------------------------------------------------------------------------- /documents/vidcontrolsadmin-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: vidcontrolsadmin # 2 | 3 | # 1. Functional Description # 4 | 5 | This component displays a set of controls to the moderator of a call. These controls get displayed underneath the video. 6 | 7 | # 2. Visual Design # 8 | 9 | ![A sample set of admin controls](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/admin-img%202.png) 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | 18 | | Prop Name | Sample | Description | 19 | | ------------ | ------------- | ------------- | 20 | | currLayout | currLayout = [] | This prop is an array and is not required. This prop provides the communicator with information on how to position the different video windows. | 21 | | layouts | layouts=[] | This prop is an array and is not required. This prop provides a list of all the possible video layouts. | 22 | | cbPlay | function cbPlay = {...} | This prop is a callback function and is required. | 23 | | cbStop | function cbStop = {...} | This prop is a callback function and is required. | 24 | | cbRecord | function cbRecord = {...} | This prop is a callback function and is required. | 25 | | cbStopRecord | function cbStopRecord = {...} | This prop is a callback function and is required. | 26 | | cbSnapshot | function cbSnapshot = {...} | This prop is a callback function and is required. | 27 | | cbSetVideoMode | function cbSetVideoMode = {...} | This prop is a callback function and is required. | 28 | 29 | 30 | 31 | 32 | ## b. Component State ## 33 | 34 | This component will maintain it's own state for presentational purposes. 35 | 36 | ## c .Component Events ## 37 | 38 | | Event | Action(s) | 39 | | ------------ | ------------- | 40 | | video mode icon clicked | 1 .Invoke the callback function cbSetVideoMode() 2. Creates a menu where the admin can select what video layout to use for this call. | 41 | 42 | ## d. Context-Aware Specification ## 43 | 44 | This component is NOT a context-aware component 45 | 46 | # 5. Reference Components # 47 | 48 | - vertobase 49 | - controlItem 50 | - tooltip 51 | - ListSelect 52 | - inputModal 53 | 54 | # 6. Unit Testing Requirement # 55 | 56 | Unit tests can be found in src/tests. 57 | -------------------------------------------------------------------------------- /src/components/about.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import Modal from 'react-modal'; 4 | import { FormattedMessage } from 'react-intl'; 5 | import WhiteLabel from '../js/whitelabel.js'; 6 | 7 | const propTypes = { 8 | compStyle: React.PropTypes.object, 9 | version: React.PropTypes.string, 10 | gitRev: React.PropTypes.string, 11 | cbClose: React.PropTypes.func.isRequired 12 | }; 13 | 14 | class About extends VertoBaseComponent{ 15 | constructor(props) { 16 | super(props); 17 | } 18 | 19 | getDefaultStyle(styleName) { 20 | const styles = { 21 | 22 | gitRevStyle: { 23 | paddingTop: '15px' 24 | }, 25 | 26 | imageStyle: { 27 | width: '100%', 28 | height: '100%' 29 | }, 30 | 31 | mymodal : { 32 | content: { 33 | top: '50%', 34 | left: '50%', 35 | right: 'auto', 36 | bottom: 'auto', 37 | marginRight: '-50%', 38 | transform: 'translate(-50%, -50%)', 39 | boxShadow: '0px 27px 24px 0px rgba(0,0,0,.2), 0px 40px 77px 0px rgba(0,0,0,.22)' 40 | }, 41 | overlay: { 42 | zIndex: "1" 43 | } 44 | }, 45 | logoSrcStyle: { 46 | width: '100%' 47 | } 48 | }; 49 | 50 | return (styles[styleName]); 51 | } 52 | 53 | render() { 54 | const logoSrc = WhiteLabel.get('logoSrc'); 55 | const poweredBy = WhiteLabel.get('poweredBy'); 56 | return ( 57 | 58 |
    59 |
    60 | 61 |
    62 | 63 |
    64 | 65 | {this.props.version} 66 |
    67 | 68 |
    69 | 70 | 71 |
    72 |
    73 |
    74 | ); 75 | } 76 | } 77 | 78 | About.propTypes = propTypes; 79 | 80 | export default About; 81 | 82 | // reviewed 7/13/2016 83 | -------------------------------------------------------------------------------- /documents/dialpad-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: Dialpad # 2 | # 1. Functional Description # 3 | 4 | The Dialpad is an area that displays the specific information and tools necessary for placing a ca 5 | 6 | # 3. Visual Design # 7 | 8 | ![Dialpad](./img/dialpad.png) 9 | 10 | # 4. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | nbrToDial | nbrToDial="8"| nbrToDial is an optional that takes a string. | 19 | | compStyle | compStyle={} | compStyle is an object that defines styles for the dialpad component. | 20 | | cbCall | cbCall={()=>{}} | cbCall is a required callback function. | 21 | | lastCall | lastCall="8"| lastCall is an optional prop that displays the last call dialed. | 22 | 23 | 24 | ## b. Component State ## 25 | 26 | This component will maintain it's own state for presentational purposes. 27 | 28 | ## c. Component Events ## 29 | 30 | Event | Action(s) 31 | ------------ | ------------- 32 | Enter/Return key pressed | 1 .Invoke the callback function cbSubmit() with the current value of the input control as an argument.
    2. Clear the input control so that placeholder text is displayed
    3. Keep focus on input control 33 | 34 | 35 | ## d. Context-Aware Specification ## 36 | 37 | This component is NOT a context-aware component 38 | 39 | # 5. Reference Components # 40 | 41 | - Radium 42 | - VertoBaseComponent 43 | - ReactIntl 44 | - SvgIcons 45 | 46 | 47 | # 6. Unit Testing Requirement # 48 | - If Numberpad area is active then SVGS render. 49 | - If Numberpad area is inactive then SVGS don't render. 50 | - If input area is active then animation renders. 51 | - If input area is inactive then animation does NOT render. 52 | - If Call History SVG is clicked then Call History is opened. 53 | - If Back SVG is clicked then the last value in the input area is erased. 54 | - (Call History) If extension number is clicked then it dials extension number. 55 | - If arrow SVG is clicked then it adds extension number to input area. 56 | - If Hamburger Menu SVG is clicked then it displays call history for that number. 57 | - If back arrow SVG is clicked then it displays main call history page. 58 | - If '...' SVG is clicked then it renders a dropdown. 59 | - If 'Clear History' is clicked then it clears history. 60 | - If there are no calls then it renders 'No history calls' 61 | -------------------------------------------------------------------------------- /src/tests/volumemeter-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import VolumeMeter from '../components/volumeMeter'; 7 | 8 | jest.unmock('../components/volumeMeter.js'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../js/messages.js'); 11 | 12 | describe('Default test for VolumeMeter', ()=>{ 13 | 14 | it('renders 5 segments as well as the icon', () => { 15 | const wrapper = shallow(); 16 | expect(wrapper.find('div').length).toEqual(6); 17 | }); 18 | 19 | it('renders 1 filled segment at a "volume level" of 2', () => { 20 | const wrapper = mountWithIntl( ); 21 | //console.log(wrapper.find('#1').props().style.backgroundColor); 22 | expect(wrapper.find('#1').props().style.backgroundColor).toEqual('#ccc'); 23 | }); 24 | 25 | it('renders 4 un-filled segments at a "volume level" of 2', () => { 26 | const wrapper = mountWithIntl( ); 27 | //console.log(wrapper.find('#3' && '#2').props().style.backgroundColor); 28 | expect(wrapper.find('#2' && '#3' && '#4' && '#5').props().style.backgroundColor).toEqual(undefined); 29 | }); 30 | 31 | it('renders 3 filled segments at a "volume level" of 70', () => { 32 | const wrapper = mountWithIntl( ); 33 | expect(wrapper.find('#1' && '#2' && '#3').props().style.backgroundColor).toEqual('#ccc'); 34 | }); 35 | 36 | it('renders 2 un-filled segments at a "volume level" of 70', () => { 37 | const wrapper = mountWithIntl( ); 38 | expect(wrapper.find('#4' && '#5').props().style.backgroundColor).toEqual(undefined); 39 | }); 40 | 41 | it('renders 5 filled segments at a "volume level" of 9001', () => { 42 | const wrapper = mountWithIntl( ); 43 | expect(wrapper.find('#1' && '#2' && '#3' && '#4' && '#5').props().style.backgroundColor).toEqual('#ccc'); 44 | }); 45 | 46 | it('renders 0 un-filled segments at a "volume level" of 9001', () => { 47 | const wrapper = mountWithIntl( ); 48 | expect(wrapper.find('#1' && '#2' && '#3' && '#4' && '#5').props().style.backgroundColor).not.toEqual(undefined); 49 | }); 50 | 51 | 52 | }); 53 | -------------------------------------------------------------------------------- /src/components/contributors.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import Modal from 'react-modal'; 4 | import App from './app'; 5 | import ContributorsListItem from './contributorsListItem'; 6 | import Radium from 'radium'; 7 | import { FormattedMessage } from 'react-intl'; 8 | 9 | const propTypes = { 10 | compStyle : React.PropTypes.object, 11 | contributorsData: React.PropTypes.array.isRequired 12 | }; 13 | 14 | class Contributors extends VertoBaseComponent{ 15 | 16 | constructor(props) { 17 | super(props); 18 | } 19 | 20 | 21 | getDefaultStyle(styleName) { 22 | const styles = { 23 | modal: { 24 | content : { 25 | top : '50%', 26 | left : '50%', 27 | right : 'auto', 28 | bottom : 'auto', 29 | marginRight : '-50%', 30 | transform : 'translate(-50%, -50%)', 31 | width: '33.33%', 32 | boxShadow: '0px 27px 24px 0px rgba(0,0,0,.2), 0px 40px 77px 0px rgba(0,0,0,.22)', 33 | borderRadius: '2px', 34 | border: 'none', 35 | backgroundColor: '#fff' 36 | }, 37 | overlay: { 38 | zIndex: "1" 39 | } 40 | }, 41 | header : { 42 | fontWeight: '300', 43 | fontSize: '24px', 44 | display: 'flex', 45 | justifyContent: 'center' 46 | }, 47 | scrollContent: { 48 | maxHeight: '540px', //list will scroll on overflow 49 | overflow: 'auto' 50 | } 51 | }; 52 | 53 | return (styles[styleName]); 54 | } 55 | 56 | render() { 57 | return ( 58 | { 59 | // console.log('closing'); 60 | App.toggleModal(); 61 | }} style={{...this.getStyle('modal')}} > 62 |
    63 |

    64 | 68 |

    69 |
    70 |
    71 | {(this.props.contributorsData).map((cont,index) => { 72 | return(); 73 | })} 74 |
    75 |
    76 | ); 77 | } 78 | } 79 | 80 | Contributors.propTypes = propTypes; 81 | 82 | export default Radium(Contributors); 83 | // reviewed 7/13/2016 84 | -------------------------------------------------------------------------------- /documents/vidcontrolsuser-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: vidControlsUser # 2 | # 1. Functional Description # 3 | 4 | This component displays 5 controls to modify either a user's video or audio. These controls will always show for the user. When a control is hovered over a tooltip will show. 5 | 6 | # 2. Visual Design # 7 | 8 | We are changing the style from the original verto. Will ad an image when the styles are done. 9 | 10 | # 3. Component Type # 11 | 12 | This component will be a 'pure' component. 13 | 14 | ## a. Required Props ## 15 | 16 | | Prop Name | Sample | Description | 17 | | ------------ | ------------- | ------------- | 18 | | cbMicMute | function cbMicMute = {...} | This prop is a function and is required. This function gets called when the mic or video status icon is clicked. | 19 | | compStyle| compStyle = {} | This prop styles the user controls. | 20 | | cbScreenShare| function cbScreenShare = {...} | This prop is a function and is required. This function gets called when the screen share icon is clicked | 21 | | cbToggleChat | function cbToggleChat = {...} | This prop is a function and is required. This function gets called when the chat icon is clicked. If chat is open the function will cause the the chat the close when clicked. | 22 | | userConfStatus | userConfStatus = {} | This prop is an object and is not required. This prop is used in checking if a user's video or audio is muted. | 23 | | newMsgCount | newMsgCount = 88 | This prop is used in printing out the badge for the chat icon. This prop is a representation how many new messages have been added to the chat since the chat was hidden. | 24 | 25 | ## b. Component State ## 26 | 27 | This component will maintain it's own state for presentational purposes. 28 | 29 | ## c .Component Events ## 30 | 31 | | Event | Action(s) | 32 | | ------------ | ------------- | 33 | | Mic/Video status icon clicked | 1 .Invoke the callback function cbMicMute() 2. Changes the SVG to properly denote the change that was made. | 34 | | screenshare icon clicked | 1 .Invoke the callback function cbScreenShare. | 35 | | chat icon clicked | 1 .Invoke the callback function cbScreenShare. 2. Toggles the chat to either display or not to display based on the previous status of the chat menu. | 36 | 37 | ## d. Context-Aware Specification ## 38 | 39 | This component is NOT a context-aware component 40 | 41 | # 4. Reference Components # 42 | 43 | - vertobase 44 | - controlItem 45 | - tooltip 46 | 47 | # 6. Unit Testing Requirement # 48 | 49 | Tests can be found in src/tests 50 | -------------------------------------------------------------------------------- /src/tests/membersadmincontrols-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import AdminControls from '../components/memberAdminControlPanel'; 7 | //import moment from 'moment'; 8 | 9 | jest.unmock('../components/memberAdminControlPanel'); 10 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 11 | jest.unmock('../js/messages.js'); 12 | //jest.unmock('moment'); 13 | 14 | const sampleMember = { 15 | callerId: "Cory", 16 | codec: "opus@48000", 17 | memberId: "0000", 18 | name: "Cory", 19 | avatar: { 20 | email: "Cory@schimmoeller.net", 21 | avatar: "http://gravatar.com/avatar/2456ab4d05ef8d750b6d7492839e32d7.png?s=75" 22 | }, 23 | conferenceStatus: { 24 | oldStatus: "floor", 25 | video: { 26 | avatarPresented:false, 27 | floor:true, 28 | mediaFlow:"sendRecv", 29 | muted:true, 30 | reservationID:null, 31 | videoLayerID:0, 32 | videoOnly:false, 33 | visible:false 34 | }, 35 | audio: { 36 | energyScore:515, 37 | floor: true, 38 | muted: false, 39 | onHold: false, 40 | talking: false 41 | } 42 | } 43 | }; 44 | 45 | describe('Default test for ChatMessageItem', ()=>{ 46 | 47 | //for some reason I can't find the ControlItems so I have to just look for some lame divs.... 48 | it('Renders the correct amount of SVGs when there is only one canvas', () => { 49 | const wrapper = mountWithIntl({}} />); 50 | expect(wrapper.find('div').length).toEqual(16); 51 | }); 52 | 53 | it('Renders the correct amount of SVGs when there are multiple canvases ', () => { 54 | const wrapper = mountWithIntl({}} />); 55 | expect(wrapper.find('div').length).toEqual(21); 56 | }); 57 | 58 | it('Properly takes in the props ', () => { 59 | const wrapper = mountWithIntl({}} />); 60 | expect(wrapper.props().multCanvas).toEqual(true); 61 | }); 62 | 63 | it('Properly takes in the props ', () => { 64 | const wrapper = mountWithIntl({}} />); 65 | expect(wrapper.props().member.name).toEqual('Cory'); 66 | }); 67 | 68 | }); 69 | -------------------------------------------------------------------------------- /src/tests/browserInfo-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | //import TestUtils from 'react-addons-test-utils'; 7 | 8 | import BrowserInfo from '../components/browserInfo.js'; 9 | 10 | jest.unmock('../components/browserInfo.js'); 11 | jest.unmock('../components/svgIcons.js'); 12 | 13 | describe('Browser Info Component', ()=>{ 14 | 15 | const browserData = { 16 | icon: 'ChromeBrowserIconSVG', 17 | name: 'Chrome', 18 | link: 'https://www.google.com/chrome/browser/desktop/', 19 | version: 'All' 20 | } 21 | 22 | it('renders four
    tags', () => { 23 | //expect(true).toBe(true); 24 | const wrapper = shallow( 25 | ); 26 | expect(wrapper.find('div').length).toEqual(4); 27 | }); 28 | 29 | it('renders an tag', () => { 30 | //expect(true).toBe(true); 31 | const wrapper = shallow( 32 | ); 33 | expect(wrapper.find('a').length).toEqual(1); 34 | }); 35 | 36 | it('browserData not undefined', () => { 37 | //expect(true).toBe(true); 38 | const wrapper = shallow(); 39 | expect(wrapper.props().browserData).toBeDefined; 40 | }); 41 | 42 | it('does not render compStyle if not provided', () =>{ 43 | const wrapper = shallow(); 44 | expect(wrapper.prop('compStyle')).toEqual(undefined); 45 | }); 46 | 47 | it('does not renders compStyle if provided', () =>{ 48 | const wrapper = mount(); 49 | expect(wrapper.find('BrowserInfo').props().compStyle.height).toEqual('30px'); 50 | }); 51 | 52 | it('renders if bnsInfoStyle is provided', () => { 53 | const wrapper = shallow() 54 | console.log('------>', wrapper.prop('style')); 55 | expect(wrapper.prop('style')).toEqual({display: 'inline-block', width: '11rem', textAlign: 'center'}); 56 | }); 57 | 58 | it('does not renders browserIconStyle if provided', () =>{ 59 | const wrapper = mount(); 60 | expect(wrapper.find('BrowserInfo').props().browserIconStyle.paddingLeft).toEqual('1rem'); 61 | }); 62 | 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-verto-communicator", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server", 8 | "test": "jest ", 9 | "build": "NODE_ENV=production webpack -p && cd dist; tar cvf ../verto.tar .", 10 | "ui-test": "node ./node_modules/ui-harness/start --entry='./src/ui-test/specs'" 11 | }, 12 | "author": "Star2Star", 13 | "license": "MIT", 14 | "dependencies": { 15 | "halogen": "^0.2.0", 16 | "json-loader": "^0.5.4", 17 | "md5": "^2.1.0", 18 | "moment": "^2.13.0", 19 | "object-merge": "^2.5.1", 20 | "radium": "^0.17.1", 21 | "react": "^15.0.2", 22 | "react-dom": "^15.0.2", 23 | "react-intl": "^2.1.2", 24 | "react-modal": "^1.3.0", 25 | "react-motion": "^0.4.4", 26 | "react-redux": "^4.4.5", 27 | "react-router": "^2.4.1", 28 | "redux": "^3.5.2", 29 | "redux-thunk": "^2.1.0", 30 | "redux-tooltip": "git://github.com/gtoma4/redux-tooltip.git", 31 | "volume-meter": "^2.0.1" 32 | }, 33 | "devDependencies": { 34 | "babel-core": "^6.9.0", 35 | "babel-eslint": "^6.0.4", 36 | "babel-jest": "^12.1.0", 37 | "babel-loader": "^6.2.4", 38 | "babel-preset-es2015": "^6.9.0", 39 | "babel-preset-react": "^6.5.0", 40 | "babel-preset-stage-0": "^6.5.0", 41 | "copy-webpack-plugin": "^3.0.1", 42 | "enzyme": "^2.3.0", 43 | "jest-cli": "^12.1.1", 44 | "react-addons-test-utils": "^15.1.0", 45 | "react-hot-loader": "^1.3.0", 46 | "sinon": "^1.17.4", 47 | "ui-harness": "^3.9.4", 48 | "webpack": "^1.13.0", 49 | "webpack-dev-server": "^1.13.0" 50 | }, 51 | "babel": { 52 | "presets": [ 53 | "es2015", 54 | "react", 55 | "stage-0" 56 | ] 57 | }, 58 | "jest-babel": { 59 | "stage": 0 60 | }, 61 | "jest": { 62 | "scriptPreprocessor": "/node_modules/babel-jest", 63 | "testDirectoryName": "tests", 64 | "testPathIgnorePatterns": [ 65 | "/specs/" 66 | ], 67 | "unmockedModulePathPatterns": [ 68 | "/node_modules/react", 69 | "/node_modules/react-dom", 70 | "/node_modules/react-tools", 71 | "/node_modules/react-addons-test-utils", 72 | "/node_modules/enzyme", 73 | "/node_modules/sinon", 74 | "/node_modules/radium", 75 | "/src/components" 76 | ] 77 | }, 78 | "repository": { 79 | "type": "git", 80 | "url": "https://github.com/star2star/react-verto-communicator" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/components/numberitem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | //import SvgIcons from './svgIcons'; 4 | import Radium from 'radium'; 5 | 6 | const propTypes = { 7 | compStyle : React.PropTypes.object, 8 | cbClick: React.PropTypes.func.isRequired, 9 | cbKeyPress : React.PropTypes.func, 10 | keyValue: React.PropTypes.string, 11 | keyString : React.PropTypes.string 12 | }; 13 | 14 | class NumberItem extends VertoBaseComponent { 15 | constructor(props) { 16 | super(props); 17 | this.state = {'onHover': false, 'onFocus': false}; 18 | 19 | this.numberClicked = this.numberClicked.bind(this); 20 | } 21 | 22 | numberClicked(){ 23 | this.props.cbClick(this.props.keyValue); 24 | } 25 | 26 | 27 | getDefaultStyle(styleName) { 28 | const styles = { 29 | container: { 30 | display: 'flex', 31 | alignItems: 'center', 32 | justifyContent: 'flex-start', 33 | flexDirection: 'column', 34 | width: '33.33%', 35 | backgroundColor: '#fff', 36 | cursor: 'pointer', 37 | padding: '0px', 38 | margin: '5px', 39 | transition: 'box-shadow .2s ease', 40 | outline: 'none', 41 | ':hover': { 42 | boxShadow: '2px 2px 5px #ddd, -2px 2px 5px #ddd' 43 | } 44 | 45 | }, 46 | keyValue: { 47 | padding: '10px 0px', 48 | color: '#26ccda', 49 | fontSize: '30px', 50 | fontWeight: '300' 51 | }, 52 | keyString: { 53 | color: '#ccc', 54 | fontSize: '11px' 55 | } 56 | }; 57 | return (styles[styleName]); 58 | } 59 | 60 | render(){ 61 | return ( 62 |
    { 68 | this.setState({...this.state, onFocus: true}); 69 | }} 70 | onClick={this.numberClicked} 71 | > 72 |
    76 | {this.props.keyValue} 77 |
    78 |
    81 | {this.props.keyString} 82 |
    83 |
    84 | ); 85 | } 86 | } 87 | 88 | NumberItem.propTypes = propTypes; 89 | 90 | export default Radium(NumberItem); 91 | // reviewed on 7/14/2016 92 | -------------------------------------------------------------------------------- /src/components/chatMessageList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ReactDOM from 'react-dom'; 4 | import ChatMessageItem from './chatMessageItem'; 5 | 6 | const propTypes = { 7 | chatItems : React.PropTypes.array, 8 | chatUsers : React.PropTypes.object, 9 | compStyle : React.PropTypes.object 10 | }; 11 | 12 | class ChatMessageList extends VertoBaseComponent { 13 | constructor(props){ 14 | super(props); 15 | this.state = {}; 16 | //console.log('ChatMessageList chatItems prop', this.props.chatItems); 17 | } 18 | 19 | componentDidUpdate() { 20 | // scroll to bottom of message list 21 | const node = ReactDOM.findDOMNode(this); 22 | node.scrollTop = node.scrollHeight; 23 | } 24 | 25 | componentDidMount() { 26 | // scroll to bottom of message list 27 | const node = ReactDOM.findDOMNode(this); 28 | node.scrollTop = node.scrollHeight; 29 | } 30 | 31 | 32 | getDefaultStyle(styleName) { 33 | const styles = { 34 | CMLStyles : { 35 | flex: 1, 36 | borderLeft: '1px solid #d1d1d1', 37 | backgroundColor: '#FAFAFA', 38 | overflowY: 'auto' 39 | } 40 | }; 41 | 42 | return styles[styleName]; 43 | } 44 | 45 | getAvatar(displayName) { 46 | // get the avatar url from gravatar if it exists and if the user displayName 47 | // is unique. Don't want to pull the wrong avatar. 48 | const displayNameArray = Object.keys(this.props.chatUsers).map((callId)=>{ 49 | return( {displayName: this.props.chatUsers[callId].name, 50 | avatarUrl: this.props.chatUsers[callId].avatar.avatar} 51 | ); 52 | }).filter((user)=>{ 53 | return(displayName == user.displayName); 54 | }); 55 | 56 | if (displayNameArray.length > 1) { 57 | return (undefined); 58 | } else { 59 | return (displayNameArray[0].avatarUrl); 60 | } 61 | } 62 | 63 | 64 | render(){ 65 | //console.log("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", this.props.chatUsers); 66 | return( 67 |
    68 | {this.props.chatItems.map((msgObj, index)=>{ 69 | const avatarUrl = this.getAvatar(msgObj.displayName); 70 | 71 | return ( ); 72 | })} 73 |
    74 | ); 75 | } 76 | } 77 | 78 | ChatMessageList.propTypes = propTypes; 79 | 80 | export default ChatMessageList; 81 | // reviewed 7/13/2016 82 | -------------------------------------------------------------------------------- /documents/callprogress-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: CallProgress # 2 | # 1. Functional Description # 3 | 4 | This component displays a set of relevant information and controls to a user when they are in a call. This information includes what extension they are currently dialed into and how long the call has been going on for. 5 | 6 | # 2. Visual Design # 7 | 8 | ![an example of a call progress bar when logged in as an admin](https://raw.githubusercontent.com/star2star/react-verto-communicator/master/documents/img/progress-img.png) 9 | 10 | 11 | # 3. Component Type # 12 | 13 | This component will be a 'pure' component. 14 | 15 | ## a. Required Props ## 16 | 17 | | Prop Name | Sample | Description | 18 | | ------------ | ------------- | ------------- | 19 | | callData | callData = {} | This prop is an object and is required. This prop provides information on the current call. | 20 | | cbDTMF | function cbDTMF = {...} | This prop is a callback function and is required. | 21 | | cbHangup | function cbHangup = {...} | This prop is a callback function and is required. | 22 | | cbHold | function cbHold = {...} | This prop is a callback function and is required. | 23 | | cbMute | function cbMute = {...} | This prop is a callback function and is required. | 24 | | cbSetVideoMode | function cbSetVideoMode = {...} | This prop is a callback function and is required. | 25 | | cbShare | function cbShare = {...} | This prop is a callback function and is required. | 26 | | cbToggleChat | function cbToggleChat = {...} | This prop is a callback function and is required. | 27 | | currLayout | currLayout = [] | This prop is an array and is not required. This prop provides the component with information on the current layout of the video. | 28 | | layouts | layouts=[] | This prop is an array and is not required. This prop provides a list of all the possible video layouts. | 29 | | newMsgCount | newMsgCount = 3 | This prop is a number and is not required. This prop tells the badge above the chat icon exactly what number to print. | 30 | | userConfStatus | userConfStatus = {} | This prop is an object and is not required. This prop tells the component if a user is in a call or not. | 31 | 32 | ## b. Component State ## 33 | 34 | This component will maintain it's own state for presentational purposes. 35 | 36 | ## c. Context-Aware Specification ## 37 | 38 | This component is NOT a context-aware component 39 | 40 | # 5. Reference Components # 41 | 42 | - vertobase 43 | - UserVideoControls 44 | - AdminVideoControls 45 | - svgIcons 46 | 47 | # 6. Unit Testing Requirement # 48 | 49 | Unit tests can be found in src/tests. 50 | -------------------------------------------------------------------------------- /src/components/splashmessage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | errorObject: React.PropTypes.object, 6 | compStyle: React.PropTypes.object, 7 | statusTitle: React.PropTypes.string.isRequired 8 | }; 9 | 10 | class SplashMessage extends VertoBaseComponent{ 11 | constructor(props) { 12 | super(props); 13 | } 14 | 15 | 16 | 17 | getDefaultStyle(styleName) { 18 | const styles = { 19 | combinedStyle: { 20 | width: "95%", 21 | margin: "0 2.5%", 22 | paddingTop: "20px" 23 | }, 24 | titleStyle: { 25 | color: "#272727", 26 | alignSelf: "center", 27 | display: "flex", 28 | flexDirection: "column", 29 | textAlign: "center", 30 | paddingBottom: "10px" 31 | }, 32 | headerStyle: { 33 | color: "#FFFFFF", 34 | flex: "1", 35 | alignSelf: "center", 36 | fontSize: "20px", 37 | padding: "5px 0px", 38 | paddingTop: "10px" 39 | }, 40 | bodyStyle: { 41 | color: "#FFFFFF", 42 | textAlign: "center", 43 | alignSelf: "center", 44 | width: "95%", 45 | backgroundColor: "#E16565", 46 | fontWeight: "500", 47 | wordWrap: "break-word", 48 | padding: "5px" 49 | }, 50 | errorStyle: { 51 | backgroundColor: "#FC7E7E", 52 | display: "flex", 53 | flexDirection: "column", 54 | paddingBottom: "25px", 55 | paddingTop: "5px" 56 | } 57 | }; 58 | return (styles[styleName]); 59 | } 60 | 61 | render() { 62 | let errorMessage; 63 | if(this.props.errorObject){ 64 | errorMessage = ( 65 |
    66 |
    {this.props.errorObject.header}
    67 |
    {this.props.errorObject.body}
    68 |
    69 | ); 70 | } 71 | // main return 72 | return ( 73 |
    74 |
    {this.props.statusTitle}
    75 | {errorMessage} 76 |
    77 | ); 78 | } 79 | } 80 | 81 | SplashMessage.propTypes = propTypes; 82 | export default SplashMessage; 83 | // reviewed on 7/14/2016 84 | -------------------------------------------------------------------------------- /src/components/chatInput.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | 4 | const propTypes = { 5 | cbSubmitMessage : React.PropTypes.func, 6 | sessionId: React.PropTypes.string, 7 | compStyle: React.PropTypes.object 8 | }; 9 | 10 | class ChatInput extends VertoBaseComponent { 11 | constructor(props){ 12 | super(props); 13 | this.state = {}; 14 | } 15 | 16 | handleKeyPress(e){ 17 | // send to parent 18 | if (e.charCode == 13 && this.refs.msgInput.value.length > 0) { 19 | //console.log('HANDLE SUBMIT - charcode', this.refs.filterInput.value); 20 | // call the callback function for processing text input since user 21 | // did not select from the filtered list 22 | //console.log('enter pressed....'); 23 | this.props.cbSubmitMessage(this.props.sessionId, this.refs.msgInput.value); 24 | // clear the input value 25 | this.refs.msgInput.value=''; 26 | } 27 | } 28 | 29 | 30 | 31 | getDefaultStyle(styleName) { 32 | const styles = { 33 | ChatInpStyle: { 34 | //width: '290px', 35 | // height: '56px', 36 | flex: '0 0 56px', 37 | display: 'flex', 38 | alignItems: 'center', 39 | justifyContent: 'center', 40 | backgroundColor: '#f7f8fb', 41 | borderRight: '0px', 42 | outline: 'none', 43 | marginLeft: '5px', 44 | marginRight: '5px' 45 | }, 46 | inputSpacing: { 47 | display:'flex', 48 | justifyContent:'stretch', 49 | flex: 1 50 | }, 51 | inputStyle: { 52 | display: 'flex', 53 | flex: 1, 54 | fontFamily: 'Avenir-Medium, sans-serif', 55 | justifyContent: 'stretch', 56 | height: '30px', 57 | color: '#4a4a4a', 58 | fontSize: '0.9rem', 59 | outline: 'none', 60 | border: '1px solid #d5dde0', 61 | marginLeft: '3px', 62 | marginRight: '3px', 63 | paddingLeft: '5px' 64 | } 65 | }; 66 | 67 | return styles[styleName]; 68 | } 69 | 70 | render(){ 71 | return( 72 |
    76 | 81 |
    82 | ); 83 | } 84 | } 85 | 86 | ChatInput.propTypes = propTypes; 87 | 88 | export default ChatInput; 89 | //reviewed 7/13/2016 90 | -------------------------------------------------------------------------------- /src/tests/dialpad-test.js: -------------------------------------------------------------------------------- 1 | //'use strict'; 2 | import React from 'react'; 3 | import { shallow, mount, render } from 'enzyme'; 4 | import sinon from 'sinon'; 5 | import ReactDOM from 'react-dom'; 6 | import {StyleRoot} from 'radium'; 7 | //import CallHistory from '../components/callhistory.js'; 8 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 9 | //import CallHistoryItem from '../callHistoryItem'; 10 | //import CallHistoryService from '../js/callHistory'; 11 | import Dialpad from '../components/dialpad.js'; 12 | 13 | jest.unmock('../components/dialpad.js'); 14 | jest.unmock('../components/callHistory.js'); 15 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 16 | jest.unmock('../js/messages.js'); 17 | //jest.unmock('../callHistoryItem'); 18 | //jest.unmock('../js/callHistory'); 19 | 20 | describe('', ()=>{ 21 | const lastCall = "9413569660"; 22 | const nbrToDial = "9045299947"; 23 | const a = ''; 24 | const cbCall = function() { 25 | return 'cbCall executed'; 26 | }; 27 | 28 | it('erases when back icon is clicked', () => { 29 | const onFocusStub = sinon.spy(); 30 | const wrapper = mountWithIntl(); 31 | const backIcon = wrapper.children().first().find('.back'); 32 | const inputArea = wrapper.children().first().find('.input'); 33 | 34 | //console.log(inputArea.props()); 35 | backIcon.simulate('click'); 36 | expect(onFocusStub.calledOnce, true); 37 | expect(inputArea.props().value).toEqual('904529994'); 38 | //console.log(inputArea.props()); 39 | }); 40 | 41 | it('displays lastNumber if number input is empty and dial is clicked.', () => { 42 | const onClickStub = sinon.spy(); 43 | const wrapper = mountWithIntl(); 44 | const dial = wrapper.children().first().find('.dial'); 45 | const inputArea = wrapper.children().first().find('.input'); 46 | 47 | dial.simulate('click'); 48 | expect(onClickStub.calledOnce, true); 49 | expect(inputArea.props().value).toEqual('9413569660'); 50 | }); 51 | 52 | // it('triggers a click event on callhistory icon', () => { 53 | // const onClickStub = sinon.spy(); 54 | // const wrapper = mount(); 55 | // const callhist = (wrapper.children().first().find('.callhist')); 56 | // 57 | // callhist.simulate('click'); 58 | // expect(onClickStub.calledOnce, true); 59 | // }); 60 | 61 | 62 | 63 | }); 64 | -------------------------------------------------------------------------------- /src/components/splash.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import SplashMessage from './splashmessage'; 4 | import Radium from 'radium'; 5 | 6 | const propTypes = { 7 | step: React.PropTypes.shape({ 8 | number: React.PropTypes.number, 9 | current: React.PropTypes.number, 10 | title: React.PropTypes.string 11 | }).isRequired, 12 | title: React.PropTypes.string, 13 | compStyle : React.PropTypes.object 14 | }; 15 | 16 | class Splash extends VertoBaseComponent { 17 | constructor(props) { 18 | super(props); 19 | this.getProgressBarWidth = this.getProgressBarWidth.bind(this); 20 | Splash.getProgressBarWidth = this.getProgressBarWidth.bind(this); 21 | 22 | } 23 | 24 | 25 | 26 | getDefaultStyle(styleName) { 27 | const styles = { 28 | splashStyle: { 29 | display: "flex", 30 | flexDirection: "column", 31 | paddingTop: "20px", 32 | paddingBottom: "20px", 33 | alignItems: "center", 34 | width: "600px", 35 | margin: "auto", // for centering in viewport 36 | background: "#FFFFFF", 37 | color: '#282828', 38 | boxShadow: ' 0px 2px 2.5px #D3D3D3, -2.5px 2px 3.75px #D3D3D3, 2.5px 2px 3.75px #D3D3D3', 39 | '@media (max-width: 991px)': { 40 | width: '80vw' 41 | } 42 | }, 43 | loadingStyle: { 44 | paddingBottom: "20px", 45 | paddingTop: "15px", 46 | fontSize: "30px", 47 | fontWeight: "200" 48 | }, 49 | loadingBarStyle: { 50 | position: "relative", 51 | width: "90%", 52 | height: "4px", 53 | backgroundColor: "#C8C8C8" 54 | }, 55 | loadingBarFilled: { 56 | position: "absolute", 57 | height: "100%", 58 | backgroundColor: "#26A599" 59 | } 60 | }; 61 | return (styles[styleName]); 62 | } 63 | 64 | // testability change 65 | getProgressBarWidth(aStepObject) { 66 | return Math.ceil(aStepObject.current/aStepObject.number * 100) ; 67 | } 68 | 69 | render() { 70 | 71 | //calc for progress bar width 72 | const progressWidth = this.getProgressBarWidth(this.props.step) + "%"; 73 | return ( 74 |
    75 |
    {this.props.title}
    76 | {/* progress bar */} 77 |
    78 |
    79 |
    80 | 81 |
    ); 82 | } 83 | } 84 | 85 | Splash.propTypes = propTypes; 86 | 87 | export default Radium(Splash); 88 | // reviewed on 7/14/2016 89 | -------------------------------------------------------------------------------- /src/components/vcstatus.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import { StatusIconSVG } from './svgIcons'; 4 | import ToolTip from './tooltip'; 5 | import { injectIntl } from 'react-intl'; 6 | 7 | const propTypes = { 8 | status: React.PropTypes.oneOf(['connected','disconnected', 'connecting', 'active']).isRequired, 9 | compStyle: React.PropTypes.object, 10 | ttPosition: React.PropTypes.string.isRequired 11 | }; 12 | 13 | class VCStatus extends VertoBaseComponent { 14 | constructor(props) { 15 | super(props); 16 | } 17 | 18 | 19 | getDefaultStyle(styleName) { 20 | const styles = { 21 | svgStyle: { 22 | width: '24px', 23 | height: '24px' 24 | }, 25 | disconnectedFill: { 26 | fill: "#F45A5A" 27 | }, 28 | connectingFill: { 29 | fill: "#F7D965" 30 | }, 31 | connectedFill: { 32 | fill: "#4ACF55" 33 | } 34 | }; 35 | return (styles[styleName]); 36 | } 37 | 38 | render() { 39 | const { formatMessage } = this.props.intl; 40 | let fillColor; 41 | let intlStatus; 42 | switch (this.props.status) { 43 | case 'disconnected': 44 | fillColor = this.getStyle('disconnectedFill'); 45 | intlStatus = formatMessage({"id":"DISCONNECTED", "defaultMessage":"Disconnected"}); 46 | break; 47 | case 'connecting': 48 | fillColor = this.getStyle('connectingFill'); 49 | intlStatus = formatMessage({"id":"CONNECTING", "defaultMessage":"Connecting"}); 50 | break; 51 | case 'active': 52 | fillColor = this.getStyle('connectingFill'); 53 | intlStatus = formatMessage({"id":"ACTIVE", "defaultMessage":"Active"}); 54 | break; 55 | case 'connected': 56 | fillColor = this.getStyle('connectedFill'); 57 | intlStatus = formatMessage({"id":"CONNECTED", "defaultMessage":"Connected"}); 58 | break; 59 | default: 60 | fillColor = this.getDefaultStyle('disconnectedFill'); 61 | intlStatus = formatMessage({"id":"DISCONNECTED", "defaultMessage":"Disconnected"}); 62 | break; 63 | } 64 | 65 | //console.log("$$$$$$$$$$$$$$$$$$$$$$" + intlStatus); 66 | const theMsg = formatMessage({"id":"COM_STATUS", "defaultMessage":"Communication Status: "}) + intlStatus; 67 | 68 | return ( 69 | 70 | 71 | 72 | ); 73 | } 74 | } 75 | 76 | VCStatus.propTypes = propTypes; 77 | 78 | export default injectIntl(VCStatus); 79 | // reviewed on 7/14/2016 80 | -------------------------------------------------------------------------------- /src/components/memberList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ReactDOM from 'react-dom'; 4 | import MemberItem from './memberItem'; 5 | 6 | const propTypes = { 7 | allowPresenter : React.PropTypes.bool, 8 | cbControlClick : React.PropTypes.func.isRequired, 9 | hasMultipleCanvases : React.PropTypes.bool, 10 | members : React.PropTypes.array, 11 | isModerator: React.PropTypes.bool, 12 | compStyle : React.PropTypes.object 13 | }; 14 | 15 | class MemberList extends VertoBaseComponent { 16 | constructor(props){ 17 | super(props); 18 | this.state = {}; 19 | this.closeAllAdminControls = this.closeAllAdminControls.bind(this); 20 | } 21 | 22 | componentDidUpdate() { 23 | // scroll to bottom of message list 24 | const node = ReactDOM.findDOMNode(this); 25 | node.scrollTop = node.scrollHeight; 26 | } 27 | 28 | componentDidMount() { 29 | // scroll to bottom of message list 30 | const node = ReactDOM.findDOMNode(this); 31 | node.scrollTop = node.scrollHeight; 32 | } 33 | 34 | 35 | 36 | getDefaultStyle(styleName) { 37 | const styles = { 38 | MLStyles : { 39 | flex: 1, 40 | borderLeft: '1px solid #d1d1d1', 41 | maxHeight: '100%', // need this so list will scroll on overflow... 42 | overflowY: 'auto', 43 | cursor: 'pointer' 44 | } 45 | }; 46 | 47 | return styles[styleName]; 48 | } 49 | 50 | closeAllAdminControls (member) { 51 | //console.log(member.name); 52 | if (this.state.memWithOpenControls == member.name) { 53 | this.setState({...this.state, memWithOpenControls: undefined }); 54 | } else { 55 | this.setState({...this.state, memWithOpenControls: member.name}); 56 | } 57 | } 58 | 59 | 60 | render(){ 61 | //console.log('---- ', this.props.members); 62 | return( 63 |
    64 | {this.props.members.map((mem, index)=>{ 65 | return ( 66 | ); 79 | })} 80 |
    81 | ); 82 | } 83 | } 84 | 85 | MemberList.propTypes = propTypes; 86 | 87 | export default MemberList; 88 | // reviewed on 7/14/2016 89 | -------------------------------------------------------------------------------- /src/components/chatSession.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ChatMessageList from './chatMessageList'; 4 | import ChatInput from './chatInput'; 5 | import Radium from 'radium'; 6 | 7 | const propTypes = { 8 | cbRemove : React.PropTypes.func, 9 | cbSubmitMessage: React.PropTypes.func, 10 | chatData : React.PropTypes.object, 11 | compStyle: React.PropTypes.object 12 | }; 13 | 14 | class ChatSession extends VertoBaseComponent { 15 | constructor(props){ 16 | super(props); 17 | this.state = {}; 18 | } 19 | 20 | 21 | getDefaultStyle(styleName) { 22 | const styles = { 23 | csStyles : { 24 | fontFamily: 'Avenir-Medium, sans-serif', 25 | display: 'flex', 26 | flexDirection: 'column', 27 | justifyContent: 'stretch', 28 | overflow: 'hidden', 29 | height: '100%' // fill the container height 30 | }, 31 | 32 | headerStyles : { 33 | display: 'flex', 34 | flex: '0 0 40px', 35 | flexDirection: 'row', 36 | alignItems: 'center', 37 | fontSize: '0.9rem', 38 | color: '#4a4a4a', 39 | paddingLeft: '10px', 40 | background:'#fff', 41 | borderBottom:'1px solid #d1d1d1', 42 | borderRadius:'5px 0px 0px 0px' 43 | }, 44 | //styles the ChatIconSVG in the top left corner of header 45 | chatIconStyle : { 46 | width: '24px', 47 | height: '24px', 48 | fill: '#4a4a4a' 49 | }, 50 | //styles the ExtractIconSVG in the top right corner of header 51 | extractStyle : { 52 | width: '24px', 53 | height: '24px', 54 | marginRight: '14px', 55 | fill: '#d5dde0', 56 | cursor:'pointer' 57 | }, 58 | chatDataViewStyle : { 59 | marginLeft: '10px', 60 | marginRight: 'auto', 61 | display: 'flex', 62 | flexDirection: 'column', 63 | flex: '1 1 auto' 64 | }, 65 | CMLStyles : { 66 | flex: '1', 67 | borderLeft: '0px' 68 | } 69 | }; 70 | 71 | return styles[styleName]; 72 | } 73 | 74 | render(){ 75 | //console.log('#### chatDatain Chat SEssion', this.props.chatData); 76 | return( 77 |
    78 | 83 | 87 |
    88 | ); 89 | } 90 | } 91 | 92 | ChatSession.propTypes = propTypes; 93 | 94 | export default Radium(ChatSession); 95 | // reviewed 7/13/2016 96 | -------------------------------------------------------------------------------- /src/containers/main/auth-reducers.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | 3 | const auth = (state, action)=>{ 4 | 5 | if (typeof state === 'undefined') { 6 | 7 | let lsLoginSettings; 8 | 9 | if (localStorage){ 10 | lsLoginSettings = JSON.parse(localStorage.getItem('loginSettings')); 11 | } 12 | const urlStuff = url.parse(location.href); 13 | const hostname = urlStuff.hostname === 'localhost' ? 'www.star2starglobal.com' : urlStuff.hostname; 14 | 15 | return { loginSettings :{ 16 | name: '', 17 | email: '', 18 | user: '1008', 19 | password: '1234', 20 | callerid: '', 21 | hostname: hostname, 22 | websocketurl: 'wss://' + hostname +':8082', 23 | autologin: false, 24 | ...lsLoginSettings 25 | }, 26 | sessionInfo: { 27 | }, 28 | vcStatus: 'disconnected' 29 | }; 30 | } 31 | 32 | switch (action.type) { 33 | case 'VALIDATION': 34 | return { ...state, showPage: 'splash', splash: action.data }; 35 | case "SHOW_LOGIN": 36 | return { ...state, showPage: 'login', vcStatus: 'disconnected' }; 37 | case "LOGOUT": 38 | return { ...state, showPage: 'logout', vcStatus: 'disconnected' }; 39 | case 'AUTH_SUBMIT_LOGIN': 40 | if (localStorage) { 41 | //save it 42 | action.data.autologin = true; 43 | localStorage.setItem('loginSettings', JSON.stringify(action.data)) 44 | } 45 | return { ...state, showPage: 'logout', vcStatus: 'connecting', loginSettings: action.data }; 46 | case "LOGIN_FAILED": 47 | return { ...state, showPage: 'logout', vcStatus: 'disconnected' }; 48 | case 'VERTO_LOGIN': 49 | return { ...state, showPage: 'loggedIn', vcStatus: 'active', sessionInfo: action.data }; 50 | case 'NO_MEDIA': 51 | return { ...state, showPage: 'noMedia', vcStatus: 'disconnected' }; 52 | case 'BNS': 53 | return { ...state, showPage: 'bns', vcStatus: 'disconnected' }; 54 | case 'RESOLUTION_REFRESH': 55 | return { ...state, showPage: 'resolution_refresh' }; 56 | case 'RESOLUTION_FAILED': 57 | return { ...state, showPage: 'resolution_failed' }; 58 | case 'CALLING': 59 | if (action.data.status === 'trying') { 60 | return { ...state, showPage: 'dialing', vcStatus: 'connected' }; 61 | } else { 62 | return { ...state, showPage: 'call_inprogress' }; 63 | } 64 | 65 | case 'CALLING_ERROR': 66 | return { ...state, showPage: 'loggedIn', error: action.data, vcStatus: 'active' }; 67 | case 'CALL_HUNG_UP': 68 | return { ...state, showPage: 'loggedIn', vcStatus: 'active' }; 69 | case 'SPEED_TEST_BEFORE_CALL': 70 | return { ...state, showPage: 'speed-test' }; 71 | default: 72 | return state; 73 | } 74 | }; 75 | 76 | export { auth }; 77 | -------------------------------------------------------------------------------- /src/components/tabbedContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import Radium from 'radium'; 4 | 5 | const propTypes = { 6 | activeTab: React.PropTypes.number, 7 | compStyle: React.PropTypes.object, 8 | tabLabels: React.PropTypes.array.isRequired 9 | }; 10 | 11 | class TabbedContainer extends VertoBaseComponent { 12 | constructor(props){ 13 | super(props); 14 | this.state = {activeTabIndex: this.props.activeTab ? this.props.activeTab : 0}; 15 | } 16 | 17 | handleTabClick(index) { 18 | this.setState({...this.state, activeTabIndex: index}); 19 | } 20 | 21 | 22 | 23 | getDefaultStyle(styleName) { 24 | const styles = { 25 | mainStyles: { 26 | display: 'flex', 27 | justifyContent: 'center', 28 | alignContent: 'center', 29 | flex: '0 0 36px' // keep this at constant height as flex item within tabbedContainerWrap column 30 | }, 31 | wrapStyles: { 32 | display: 'flex', 33 | flexDirection: 'column', 34 | justifyContent: 'flex-start', 35 | height: '100%' // Set up height of wrapper 36 | }, 37 | tabStyles: { 38 | flex: '1', 39 | display: 'flex', 40 | color: '#9b9b9b', 41 | flexDirection: 'row', 42 | textTransform: 'uppercase', 43 | fontWeight: '500', 44 | paddingLeft: '20px', 45 | paddingTop: '5px', 46 | justifyContent: 'center' 47 | 48 | }, 49 | containerStyles: { 50 | flex: '1', // this flex item will grow/shrink within tabbedContainerWrap column 51 | overflow: 'hidden' // need this so that the chat list and memberlist will scroll on overflow 52 | } 53 | 54 | }; 55 | 56 | return styles[styleName]; 57 | } 58 | 59 | render(){ 60 | const childToRender = React.Children.toArray(this.props.children)[this.state.activeTabIndex]; 61 | 62 | // console.log('############### props from child', childToRender.props); 63 | return( 64 |
    65 |
    66 | {this.props.tabLabels.map((label, index)=>{ 67 | let theStyle=this.getStyle("tabStyles"); 68 | if (index == this.state.activeTabIndex) { 69 | theStyle = {...theStyle, color: "#1194f6", borderBottom: "2px solid #1194f6"}; 70 | } 71 | return( 72 |
    {this.handleTabClick(index);}}>{label}
    73 | ); 74 | })} 75 |
    76 |
    77 | {childToRender} 78 |
    79 |
    80 | ); 81 | 82 | } 83 | } 84 | 85 | TabbedContainer.propTypes = propTypes; 86 | 87 | export default Radium(TabbedContainer); 88 | // reviewed on 7/14/2016 89 | -------------------------------------------------------------------------------- /documents/callhistory-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: CallHistory # 2 | # 1. Functional Description # 3 | 4 | CallHistory renders a list containing information about previously made calls. 5 | 6 | # 2. Visual Design # 7 | 8 | ![CallHistory(Left), Dialpad(Right)](./img/callhistory.png) 9 | ![CallHistory(alt state)](./img/chaltstate.png) 10 | 11 | 12 | # 3. Component Type # 13 | 14 | This component will be a 'pure' component. 15 | 16 | 17 | ## a. Required Props ## 18 | 19 | | Prop Name | Sample | Description | 20 | | ------------ | ------------- | ------------- | 21 | | history | history=[] | A required prop that is an array. | 22 | | compStyle | NOTE styles are in JSX, not CSS
    { inputWrapStyle: {backgroundColor: '#ddd'} inputStyle {fontSize: '1rem'} } | An optional property that customizes component style. | 23 | | cbBack | cbBack={()=>{}} | A required function. | 24 | | cbShowCalls | cbShowCalls={()=>{}} | A required function. | 25 | | cbClearHistory | cbClearHistory={()=>{}} | A required function.| 26 | | cbClick | cbClick={()=>{}} | A required function. | 27 | | cbCall | cbCall={()=>{}} | A required function. | 28 | | allowToolTip | allowToolTip=false | A boolean that toggles the appearance of tooltip. By default it is false.| 29 | | callerId | callerId="3500" | A string that represents an extension number. 30 | 31 | 32 | 33 | ## b. Component State ## 34 | 35 | This component will maintain it's own state for presentational purposes. 36 | 37 | ## c .Component Events ## 38 | 39 | Event | Action(s) 40 | ------------ | ------------- 41 | 'Clear History' Clicked | 1. callback function invoked.
    2. Event Dispatched
    3. Component renders blank list. 42 | 'Back' clicked | callback function invoked.
    2. State is changed
    3. New Screen Rendered 43 | 'Hamburger' Menu Clicked | 1. Callback function invoked
    2. State Change
    3. New Screen rendered 44 | 'ChatHistoryItem' clicked | 1. callback function invoked.
    2. Event Dispatched.
    45 | 46 | ## d. Context-Aware Specification ## 47 | 48 | The CallHistory component is NOT context-aware. 49 | 50 | # 4. Reference Components # 51 | 52 | - ReactIntl 53 | - VertoBaseComponent 54 | - CallHistoryItem 55 | - moment.js 56 | - react-motion 57 | - svgIcons 58 | - CallHistoryService 59 | 60 | # 5. Unit Testing Requirement # 61 | 62 | - displays a list of objects containing call history info. 63 | - displays a list of timestamps when state is changed. 64 | - displays an empty list when cbClearHistory is clicked. 65 | - displays callerId in the header when state is changed. 66 | - displays Call History in the header when state is normal. 67 | - displays an arrow svg when state is changed. 68 | - displays an x svg when state is default. 69 | - displays a 'clear history' link when state is default. 70 | - does not display a 'clear history' link when state is changed. 71 | - cbBack is invoked when x svg is clicked. 72 | - cbClearHistory is invoked when 'clear history' link is clicked. 73 | - cbBack is invoked when arrow svg is clicked. 74 | -------------------------------------------------------------------------------- /src/components/settingsMenuSelect.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent.js'; 3 | 4 | const propTypes = { 5 | cbSubmitSetting: React.PropTypes.func.isRequired, 6 | compStyle : React.PropTypes.object, 7 | label: React.PropTypes.string.isRequired, 8 | options: React.PropTypes.array.isRequired, 9 | selectedOption: React.PropTypes.object.isRequired 10 | }; 11 | 12 | class SettingsMenuSelect extends VertoBaseComponent { 13 | constructor(props) { 14 | super(props); 15 | } 16 | 17 | handleSelect() { 18 | const theSelect = this.refs.select; 19 | 20 | // get the selected option from the options array. Use [0] to get the array 21 | // element only (should only be one). 22 | const selValue = this.props.options.filter((opt)=>{ 23 | //console.log('theSelect', theSelect); 24 | return (opt.id == theSelect[theSelect.selectedIndex].value); 25 | })[0]; 26 | 27 | 28 | // The selectedOption prop has the structure that we need for the 'selected' 29 | // value in the settings store. Just replace the id and label values and 30 | // return the structure to the callback function... 31 | // The id is the name of the setting attribute to be set, and the data attribute 32 | // is the value. 33 | 34 | let selObj = {}; 35 | selObj[this.props.selectedOption.id] = {...this.props.selectedOption.data, ...selValue}; 36 | this.props.cbSubmitSetting(selObj); 37 | } 38 | 39 | 40 | 41 | getDefaultStyle(styleName) { 42 | const styles = { 43 | container: { 44 | paddingTop: '10px', 45 | paddingBottom: '5px', 46 | borderBottom: '1px solid #FFF', 47 | display: 'flex', 48 | flexDirection: 'column' 49 | }, 50 | label: { 51 | display:'flex', 52 | paddingBottom: '10px', 53 | fontWeight: 'bold', 54 | fontSize: '1rem' 55 | }, 56 | select: { 57 | border: 'none', 58 | boxShadow:'none', 59 | fontSize: '.9rem', 60 | backgroundColor: 'rgba(0,0,0,0)', 61 | color: '#FFF' 62 | } 63 | }; 64 | 65 | return (styles[styleName]); 66 | } 67 | 68 | render() { 69 | const options=this.props.options.map((option, index)=>{ 70 | return (); 71 | }); 72 | 73 | return ( 74 |
    75 | {this.props.label} 76 | 84 |
    85 | ); 86 | } 87 | } 88 | 89 | SettingsMenuSelect.propTypes = propTypes; 90 | export default SettingsMenuSelect; 91 | // reviewed on 7/14/2016 92 | -------------------------------------------------------------------------------- /src/tests/controlItem-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import ControlItem from '../components/controlItem'; 7 | 8 | jest.unmock('../components/controlItem'); 9 | jest.unmock('../helpers/intl-enzyme-test-helper.js'); 10 | jest.unmock('../components/svgIcons.js'); 11 | 12 | describe('Default test for ControlItem', ()=>{ 13 | const cbActionClick = sinon.spy(); 14 | const label = "label" 15 | 16 | it('renders two spans', () => { 17 | const wrapper = shallow( 18 | ); 22 | expect(wrapper.find('span').length).toEqual(2); 23 | }); 24 | 25 | it('renders the SVG ', () => { 26 | const wrapper = mount( 27 | ); 31 | expect(wrapper.find('RemoveIconSVG').length).toEqual(1); 32 | }); 33 | 34 | it('renders correct style', () => { 35 | const wrapper = shallow( 36 | ); 40 | // console.log('------------>>', wrapper.props().style.display); 41 | expect(wrapper.props().style.display).toEqual('flex'); 42 | }); 43 | 44 | it('renders correct style', () => { 45 | const wrapper = shallow( 46 | ); 50 | // console.log('------------>>', wrapper.childAt(0).props().svgStyle.height); 51 | expect(wrapper.childAt(0).props().svgStyle.height).toEqual('24px'); 52 | }); 53 | 54 | it('renders correct style', () => { 55 | const wrapper = shallow( 56 | ); 60 | // console.log('------------>>', wrapper.childAt(0).props().svgStyle.height); 61 | expect(wrapper.childAt(0).props().svgStyle.fill).toEqual('#6b6c6c'); 62 | }); 63 | 64 | it('displays label', () => { 65 | const wrapper = mount( 66 | ); 71 | const expectedNode = wrapper.children().find('.label'); 72 | // console.log('------------->>>', wrapper.children().find('.label')); 73 | expect(expectedNode.props().children).toEqual("label"); 74 | }); 75 | 76 | it('simulates click event (cbActionClick)', () => { 77 | const spy = sinon.spy(); 78 | const wrapper = mount( 79 | ); 84 | const expectedNode = wrapper.find('.container'); 85 | // console.log('------->>>', expectedNode.debug()); 86 | expectedNode.simulate('click'); 87 | expect(spy.calledOnce, true); 88 | }); 89 | 90 | 91 | }); 92 | -------------------------------------------------------------------------------- /src/tests/memberList-test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow, mount, render } from 'enzyme'; 3 | import sinon from 'sinon'; 4 | import ReactDOM from 'react-dom'; 5 | import { mountWithIntl, shallowWithIntl } from '../helpers/intl-enzyme-test-helper.js'; 6 | import MemberList from '../components/memberList'; 7 | import MemberItem from '../components/memberItem'; 8 | 9 | jest.unmock('../components/memberList'); 10 | jest.unmock('../components/memberItem'); 11 | // jest.unmock('../helpers/intl-enzyme-test-helper.js'); 12 | // jest.unmock('../js/messages.js'); 13 | jest.unmock('../components/svgIcons.js'); 14 | 15 | describe( 'MemberList', ()=>{ 16 | 17 | const cbControlClick= sinon.spy(); 18 | const controlSettings={ moderator: true, multCanvas: false, allowPresenter: true }; 19 | const sampleMembers = [{ 20 | callerId: "Name", 21 | codec: "opus@48000", 22 | memberId: "0000", 23 | name: "Name", 24 | avatar: { 25 | email: "Name@email.com", 26 | avatar: "http://gravatar.com/avatar/2456ab4d05ef8d750b6d7492839e32d7.png?s=75" 27 | }, 28 | conferenceStatus: { 29 | oldStatus: "floor", 30 | video: { 31 | avatarPresented:false, 32 | floor:true, 33 | mediaFlow:"sendRecv", 34 | muted:true, 35 | reservationID:null, 36 | videoLayerID:0, 37 | videoOnly:false, 38 | visible:false 39 | }, 40 | audio: { 41 | energyScore:515, 42 | floor: true, 43 | muted: false, 44 | onHold: false, 45 | talking: false 46 | } 47 | } 48 | }, 49 | { 50 | callerId: "1Name", 51 | codec: "opus@48000", 52 | memberId: "0000", 53 | name: "1Name", 54 | avatar: { 55 | email: "1Name@email.com", 56 | avatar: "http://gravatar.com/avatar/2456ab4d05ef8d750b6d7492839e32d7.png?s=75" 57 | }, 58 | conferenceStatus: { 59 | oldStatus: "floor", 60 | video: { 61 | avatarPresented:false, 62 | floor:true, 63 | mediaFlow:"sendRecv", 64 | muted:true, 65 | reservationID:null, 66 | videoLayerID:0, 67 | videoOnly:false, 68 | visible:false 69 | }, 70 | audio: { 71 | energyScore:515, 72 | floor: true, 73 | muted: true, 74 | onHold: false, 75 | talking: false 76 | } 77 | } 78 | }]; 79 | 80 | it('renders a div', () => { 81 | const wrapper = shallow( 82 | ); 87 | expect(wrapper.find('div').length).toEqual(1); 88 | }); 89 | 90 | it('Takes in & displays props correctly (name:)', () => { 91 | const wrapper = shallow( 92 | ); 97 | console.log(wrapper.props().children[0]); 98 | expect(wrapper.props().sampleMember.name).toEqual('Name'); 99 | }); 100 | 101 | }); 102 | -------------------------------------------------------------------------------- /src/tests/specs/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | // Step 1 - Import your component here... 3 | import VCStatus from "../../components/vcstatus.js"; 4 | import BNS from "../../components/browser.js" 5 | 6 | 7 | // Step 2 - Add a describe block for your component and define the appropriate tests 8 | 9 | describe("VCStatus", function() { 10 | 11 | before(() => { 12 | //type now accepts SVG name as value 13 | this.component( 14 | ); 18 | }); 19 | section('default', ()=>{ 20 | it("Reset", () => { 21 | this.component( 22 | ); 26 | }); 27 | }); 28 | 29 | section('UI', ()=>{ 30 | it("add styles", () => { 31 | this.component( 32 | ); 36 | }); 37 | }); 38 | 39 | 40 | }); 41 | 42 | /////////////////////////////////////////////////////////////////////////////// 43 | 44 | describe("BroweserNotSupported", function() { 45 | 46 | before(() => { 47 | //type now accepts SVG name as value 48 | this.component( 49 | ); 52 | }); 53 | section('default', ()=>{ 54 | it("Reset", () => { 55 | this.component( 56 | ); 58 | }); 59 | }); 60 | 61 | section('More Stuff', ()=>{ 62 | it("does stuff", () => { 63 | this.component( 64 | ); 66 | }); 67 | }); 68 | }); 69 | 70 | /* 71 | // more sample code here 72 | //import MyComponent from "../MyComponent.jsx"; 73 | const LOREM = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 74 | 75 | 76 | describe("MyComponent", function() { 77 | let count = 0; 78 | this.header(`## A Simple Component`); // Markdown. 79 | 80 | before(() => { 81 | // Runs when the Suite loads. 82 | // Use this to load your component-under-test. 83 | this.component( ); 84 | }); 85 | 86 | it("reload", () => { 87 | count += 1; 88 | this.component( ); 91 | }); 92 | 93 | section("text", () => { 94 | it("increment", () => { 95 | count += 1; 96 | this.props({ text: `My Component ${ count }` }); 97 | }); 98 | it("long", () => { this.props({ text: LOREM }) }); 99 | }); 100 | 101 | section("color", () => { 102 | it("red", () => this.props({ color: "red" })); 103 | it("green", () => this.props({ color: "green" })); 104 | it("blue", () => this.props({ color: "blue" })); 105 | it("orange (error)", () => this.props({ color: "orange" })); 106 | }); 107 | }); 108 | */ 109 | -------------------------------------------------------------------------------- /src/components/alertItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ControlItem from './controlItem'; 4 | 5 | 6 | const propTypes = { 7 | alertData: React.PropTypes.object.isRequired, 8 | cbDismissAlert : React.PropTypes.func.isRequired, 9 | compStyle : React.PropTypes.object, 10 | index : React.PropTypes.number 11 | }; 12 | 13 | class AlertItem extends VertoBaseComponent { 14 | constructor(props){ 15 | super(props); 16 | this.state = {}; 17 | 18 | this.handleDismissClick = this.handleDismissClick.bind(this); 19 | } 20 | 21 | componentDidMount() { 22 | // set timeout for removing the alert from list after 5 seconds 23 | this.alertTimeout = setTimeout(()=>{ 24 | this.props.cbDismissAlert(this.props.alertData.id); 25 | }, 5000); 26 | } 27 | 28 | componentWillUnmount() { 29 | clearTimeout(this.alertTimeout); 30 | } 31 | 32 | handleDismissClick() { 33 | clearTimeout(this.alertTimeout); 34 | this.props.cbDismissAlert(this.props.alertData.id); 35 | } 36 | 37 | getDefaultStyle(styleName) { 38 | const styles = { 39 | alertItemStyles : { 40 | display: 'flex', 41 | border: '1px solid #d1d1d1', 42 | borderRadius: '5px', 43 | backgroundColor: '#FFF', 44 | flexDirection: 'column', 45 | marginBottom: '10px', 46 | boxShadow: 'rgba(0, 0, 0, 0.1) -5px 3px 0px -4px, rgba(0, 0, 0, 0.219608) 0px 3px 7px 0px' 47 | }, 48 | headingStyles: { 49 | display: 'flex', 50 | justifyContent: 'space-between', 51 | alignItems: 'center', 52 | padding: '5px 3px 10px 10px', 53 | borderRadius: '4px 4px 0px 0px' 54 | }, 55 | compStyle : { 56 | controlStyle: { 57 | flex: 1 58 | } 59 | }, 60 | alertDetailStyle : { 61 | padding:'5px 3px 5px 10px', 62 | display:'flex', 63 | alignItems:'center', 64 | fontSize: '.85rem', 65 | backgroundColor: '#EEE', 66 | borderRadius: '0px 0px 4px 4px' 67 | } 68 | }; 69 | 70 | return styles[styleName]; 71 | } 72 | 73 | render(){ 74 | // console.log('--------------> ', this.props.alertData); 75 | let headingbgColor; 76 | switch (this.props.alertData.level) { 77 | case 'error': 78 | headingbgColor = {backgroundColor: '#FD5F56'}; 79 | break; 80 | case 'warn': 81 | headingbgColor = {backgroundColor: '#FFC02F'}; 82 | break; 83 | case 'info': 84 | default: 85 | headingbgColor = {backgroundColor: '#63B653'}; 86 | } 87 | 88 | return( 89 |
    90 |
    91 | {this.props.alertData.summary} 92 | 93 |
    94 |
    95 | {this.props.alertData.detail} 96 |
    97 |
    98 | ); 99 | } 100 | } 101 | 102 | AlertItem.propTypes = propTypes; 103 | 104 | export default AlertItem; 105 | // reviewed 7/13/2016 106 | -------------------------------------------------------------------------------- /src/components/inputModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import Modal from 'react-modal'; 4 | import Input from './input'; 5 | import { FormattedMessage } from 'react-intl'; 6 | 7 | const propTypes = { 8 | cbClose: React.PropTypes.func.isRequired, 9 | cbSubmit: React.PropTypes.func.isRequired, 10 | compStyle: React.PropTypes.object, 11 | title: React.PropTypes.string, 12 | message: React.PropTypes.string, 13 | label: React.PropTypes.string, 14 | placeholder: React.PropTypes.string 15 | }; 16 | 17 | class InputModal extends VertoBaseComponent { 18 | constructor(props) { 19 | super(props); 20 | this.state = {inputVal: ''}; 21 | this.changingInput = this.changingInput.bind(this); 22 | } 23 | 24 | 25 | 26 | getDefaultStyle(styleName) { 27 | const styles = { 28 | 29 | headingStyle: { 30 | backgroundColor: '#ccc' 31 | }, 32 | messageStyle: { 33 | 34 | }, 35 | 36 | modalStyle : { 37 | content: { 38 | top : '50%', 39 | left : '50%', 40 | right : 'auto', 41 | bottom : 'auto', 42 | marginRight : '-50%', 43 | transform : 'translate(-50%, -50%)', 44 | boxShadow : '0px 27px 24px 0px rgba(0,0,0,.2), 0px 40px 77px 0px rgba(0,0,0,.22)' 45 | }, 46 | overlay: { 47 | zIndex: "1" 48 | } 49 | } 50 | }; 51 | 52 | return (styles[styleName]); 53 | } 54 | 55 | changingInput(field, value){ 56 | //TODO - at some point rework Input component so that it is as generic as 57 | // its name implies 58 | 59 | // we don't care about the field since there is only one here right now... 60 | this.setState({...this.state, inputVal: value}); 61 | 62 | } 63 | 64 | render() { 65 | // TODO - ta INternationalize the strings here, style input, etc. 66 | 67 | return ( 68 | 69 |
    70 |
    72 | {this.props.title} 73 |
    74 |
    75 | {this.props.message} 76 |
    77 | 83 | 84 | 90 | 91 | 97 |
    98 |
    ); 99 | } 100 | } 101 | 102 | InputModal.propTypes = propTypes; 103 | 104 | export default InputModal; 105 | // reviewed on 7/13/2016 106 | -------------------------------------------------------------------------------- /documents/browser-spec.md: -------------------------------------------------------------------------------- 1 | # Component Name: < Browser\> # 2 | 3 | # 1. Functional Description # 4 | 5 | This component will appear under the App Bar when/if the user's browser is not compatible with 6 | the Verto Communicator. It uses the BrowserInfo and (possibly a version of the BrowserVideoHeader). It uses four instances of the BrowserInfo component to display vertically the browser Icon, browser Link, browser Name, & browser Version - (WhiteLabel?). 7 | All displayed text uses the FormattedMessage convention for react-itnl. The messages are in the browser.json file located in the 'messages' folder. This component will utilize the established theming convention for this project (light, dark, & default) as needed. Styles can be overridden through the style prop. 8 | 9 | # 2. Star2Star Spore Component Project - SCP # 10 | 11 | N/A 12 | 13 | # 3. Visual Design # 14 | 15 | Images: TBA 16 | 17 | # 4. Component Type # 18 | 19 | This component will be a 'pure' component. It will accept props for styling and the of the communicator. 20 | 21 | ## a. Required Props ## 22 | 23 | The Browser component does not have any required props. 24 | 25 | ## b. Component State ## 26 | The Browser component does not maintain its own state. 27 | 28 | ## c .Component Events ## 29 | (REMOVE WHEN DONE) 30 | 31 | If the component needs to react to events (clicks, key presses, etc.) then those events should be listed here along with the action that should be taken: 32 | 33 | Sample: 34 | 35 | Event | Action(s) 36 | ------------ | ------------- 37 | Enter/Return key pressed | 1 .Invoke the callback function cbSubmit() with the current value of the input control as an argument.
    2. Clear the input control so that placeholder text is displayed
    3. Keep focus on input control 38 | 39 | (REMOVE) 40 | 41 | ## d. Context-Aware Specification ## 42 | 43 | Not Context-Aware. 44 | 45 | # 5. Reference Components # 46 | 47 | The Browser component imports: 48 | - svgIcons from svgIcons.js
    49 | - VertoBaseComponent from vertobase.js
    50 | - FormattedMessage from ReactIntl
    51 | - BrowserInfo from browserInfo.js
    52 | 53 | # 6. Unit Testing Requirement # 54 | 55 | (REMOVE WHEN DONE) 56 | 57 | A unit test suite must be developed as part of the component development process. Unit tests must be provided to Star2Star and be runnable using 'npm test'. Refer to the Star2Star Unit Testing standards document. Test framework must use Jest/Jasmine, Enzyme and Sinon. 58 | 59 | Refer to the following links: 60 | * Jest: https://facebook.github.io/jest/docs/tutorial.html#content 61 | * Jasmine 2.0: http://jasmine.github.io/2.0/introduction.html 62 | * Enzyme: https://github.com/airbnb/enzyme 63 | * Sinon: http://www.sitepoint.com/sinon-tutorial-javascript-testing-mocks-spies-stubs/?utm_source=javascriptweekly&utm_medium=email 64 | * http://sinonjs.org/docs/ 65 | 66 | # 7. Deliverables # 67 | 68 | The following items must be delivered to Star2Star at the completion of the component development; full implementation of component meeting the requirements of this specification 69 | 70 | a. Complete and accurate README.md 71 | 72 | b. Unit tests must cover at least 80% branch coverage. We require using Jest for unit testing with the __--verbose__ and __--coverage__ options set. 73 | 74 | c. Component must render correctly in demo. 75 | 76 | d. Must comply to Star2Star Component Specification Standards; which includes theming, accessibility, white labeling and internationalization 77 | 78 | e. All documented functional requirements must be met. 79 | -------------------------------------------------------------------------------- /src/components/alertLogItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import VertoBaseComponent from './vertobasecomponent'; 3 | import ControlItem from './controlItem'; 4 | import moment from 'moment'; 5 | 6 | 7 | const propTypes = { 8 | alertData: React.PropTypes.object.isRequired, 9 | cbRemoveAlert : React.PropTypes.func.isRequired, 10 | compStyle : React.PropTypes.object, 11 | index : React.PropTypes.number 12 | }; 13 | 14 | class AlertLogItem extends VertoBaseComponent { 15 | constructor(props){ 16 | super(props); 17 | this.state = {}; 18 | 19 | this.handleRemoveClick = this.handleRemoveClick.bind(this); 20 | } 21 | 22 | handleRemoveClick() { 23 | this.props.cbRemoveAlert(this.props.index); 24 | } 25 | 26 | 27 | 28 | getDefaultStyle(styleName) { 29 | const styles = { 30 | alertItemStyles : { 31 | display: 'flex', 32 | border: '1px solid #d1d1d1', 33 | backgroundColor: '#FFF' 34 | }, 35 | typeTabStyles: { 36 | flex: '0 0 30px', 37 | display: 'flex', 38 | justifyContent: 'center', 39 | paddingTop: '5px', 40 | alignItems: 'flex-start' 41 | }, 42 | timestampStyles: { 43 | flex: '1', 44 | display: 'flex', 45 | alignItems: 'flex-start', 46 | paddingTop: '5px', 47 | paddingLeft: '10px', 48 | paddingRight: '5px' 49 | }, 50 | summaryStyles: { 51 | flex: '1', 52 | display: 'flex', 53 | alignItems: 'flex-start', 54 | padding: '5px' 55 | // overflowY: 'auto' 56 | }, 57 | detailStyles: { 58 | flex: '1', 59 | display: 'flex', 60 | alignItems: 'flex-start', 61 | paddingRight: '10px', 62 | paddingTop: '5px', 63 | paddingBottom: '5px' 64 | // overflowY: 'auto', 65 | }, 66 | compStyle : { 67 | controlStyle: { 68 | flex: '1' 69 | } 70 | } 71 | }; 72 | 73 | let styleReturn = styles[styleName]; 74 | return styleReturn; 75 | } 76 | 77 | render(){ 78 | //console.log('---- ', this.props.alertData); 79 | let tabbgColor; 80 | switch (this.props.alertData.level) { 81 | case 'error': 82 | tabbgColor = {backgroundColor: '#FD5F56'}; 83 | break; 84 | case 'warn': 85 | tabbgColor = {backgroundColor: '#FFC02F'}; 86 | break; 87 | case 'info': 88 | default: 89 | tabbgColor = {backgroundColor: '#63B653'}; 90 | } 91 | const formattedTimeStamp = moment(this.props.alertData.timestamp).format('ddd MMM DD YYYY HH:mm:ss A'); 92 | 93 | return( 94 |
    95 |
    96 | 97 |
    98 |
    99 | {formattedTimeStamp} 100 |
    101 |
    102 | {this.props.alertData.summary} 103 |
    104 |
    105 | {this.props.alertData.detail} 106 |
    107 |
    108 | ); 109 | } 110 | } 111 | 112 | AlertLogItem.propTypes = propTypes; 113 | 114 | export default AlertLogItem; 115 | // reviewed 7/13/2016 116 | --------------------------------------------------------------------------------