-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ActivityStream): implement empty state
- Loading branch information
Showing
12 changed files
with
557 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Webex Activity Stream Component | ||
|
||
Webex activity stream component displays a list of activities of a room. | ||
|
||
<p align="center"> | ||
<span>picture coming up</span> | ||
</p> | ||
|
||
## Preview | ||
|
||
To see all the different possible states of the Webex Activity Stream component, you can run our Storybook: | ||
|
||
```shell | ||
npm start | ||
``` | ||
|
||
## Embed | ||
|
||
1. Create a component adapter from which the data will be retrieved (See [adapters](../../adapters)). For instance: | ||
|
||
```js | ||
const jsonAdapter = new RoomsJSONAdapter(rooms); | ||
``` | ||
|
||
2. Create a component instance by passing the room ID as a string and the [component data adapter](../../adapters/RoomsAdapter.js) that we created previously | ||
|
||
```js | ||
<WebexActivityStream roomID="roomID" adapter={jsonAdapter} /> | ||
``` | ||
|
||
The component knows how to manage its data. If anything changes in the data source that the adapter manages, the component will also update on its own. |
151 changes: 151 additions & 0 deletions
151
src/components/WebexActivityStream/WebexActivityStream.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import {RoomType} from '../../adapters/RoomsAdapter'; | ||
import './WebexActivityStream.scss'; | ||
import {useRoom, useActivityStream} from '../hooks'; | ||
|
||
export function GreetingDirectSVG() { | ||
return ( | ||
<svg | ||
width="61px" | ||
height="60px" | ||
viewBox="0 0 61 60" | ||
version="1.1" | ||
xlns="http://www.w3.org/2000/svg" | ||
xlinkHref="http://www.w3.org/1999/xlink" | ||
> | ||
<g id="Page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd"> | ||
<g id="one-on-one" stroke="#343537" strokeWidth="1.12800004"> | ||
<g id="Group-39" transform="translate(9.056604, 6.895610)"> | ||
<path | ||
d="M42.2831173,43.3165345 L42.1768007,41.8220793 C41.3164233,36.6788756 36.8550615,32.9083712 31.6258573,32.9083712 L10.9787695,32.9083712 C5.75153404,32.9083712 1.28820345,36.6788756 0.429794914,41.8220793 L0.323478261,43.3126069" | ||
id="Stroke-15" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
<path | ||
d="M28.8517801,32.9472545 C31.9664643,32.2991991 35.0476784,31.2426723 38.0265135,29.7580362 L38.0265135,16.8362033 C38.0265135,7.54740855 30.4780312,0.0162187139 21.1635111,0.0162187139 C11.8509598,0.0162187139 4.30050861,7.54740855 4.30050861,16.8362033 L4.30050861,29.7580362 C6.81470057,31.0089796 10.4452174,32.279561 13.1700738,32.9472545" | ||
id="Stroke-27" | ||
/> | ||
<path | ||
d="M9.72108285,12.4414055 C11.4733388,13.1660493 13.0543068,13.7257335 14.9168171,14.1165306 L16.5942576,9.9945052 L16.6926989,14.6506854 C21.4907301,15.08665 28.1197703,14.2716712 32.8784249,12.305903 L32.9335521,12.305903 C34.1995078,14.36397 34.9279737,16.783377 34.9279737,19.373635 C34.9279737,26.8498383 28.8521739,32.9101386 21.3568499,32.9101386 C13.8615258,32.9101386 7.78375718,26.8498383 7.78375718,19.373635 C7.78375718,16.9856488 8.40393765,14.7429842 9.49269893,12.7948903 L9.72108285,12.4414055 Z" | ||
id="Stroke-29" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
</g> | ||
<path | ||
d="M59.5436259,30.0538891 C59.5436259,13.8348286 46.360361,0.685194455 30.0998195,0.685194455 C23.531813,0.685194455 17.4855455,2.85716211 12.589073,6.48430882 L8.65338802,9.97398922 C3.70769483,15.227166 0.656013126,22.2772237 0.656013126,30.0538891 C0.656013126,46.2729496 13.8392781,59.4206199 30.0998195,59.4206199 C38.5086792,59.4206199 46.0965381,55.9054101 51.4615915,50.2653639 C56.4919442,44.9493454 59.5436259,37.8560839 59.5436259,30.0538891 Z" | ||
id="Stroke-31" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
</g> | ||
</g> | ||
</svg> | ||
); | ||
} | ||
|
||
export function GreetingSpaceSVG() { | ||
return ( | ||
<svg | ||
width="61px" | ||
height="61px" | ||
viewBox="0 0 61 61" | ||
version="1.1" | ||
xmlns="http://www.w3.org/2000/svg" | ||
xlinkHref="http://www.w3.org/1999/xlink" | ||
> | ||
<g id="Page-1" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd"> | ||
<g id="space" transform="translate(-14.000000, -3.000000)"> | ||
<rect id="Rectangle-2" x="0" y="0" width="90" height="68" /> | ||
<g id="Group" transform="translate(15.000000, 4.000000)" stroke="#343537"> | ||
<path | ||
d="M1.77076923,19.42 C0.624615385,22.5692308 0,25.9676923 0,29.5123077 C0,45.8107692 13.2123077,59.0246154 29.5123077,59.0246154 C45.8107692,59.0246154 59.0246154,45.8107692 59.0246154,29.5123077 C59.0246154,13.2138462 45.8107692,0 29.5123077,0 C20.6169231,0 12.6415385,3.93538462 7.23076923,10.16" | ||
id="Stroke-9" | ||
/> | ||
<path | ||
d="M56.9563077,23.8953846 C56.9563077,17.3984615 51.6901538,12.1323077 45.1932308,12.1323077 C38.6947692,12.1323077 33.4286154,17.3984615 33.4286154,23.8953846 C33.4286154,30.3923077 38.6947692,35.6584615 45.1932308,35.6584615 C51.6901538,35.6584615 56.9563077,30.3923077 56.9563077,23.8953846 Z" | ||
id="Stroke-11" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
<path | ||
d="M32.0841538,40.082 C33.3472308,37.1358462 36.0087692,35.6589231 38.7826154,35.6589231 L51.5703077,35.6589231 C53.9856923,35.6589231 56.1887692,36.8435385 57.5349231,38.7373846" | ||
id="Stroke-13" | ||
strokeLinecap="round" | ||
/> | ||
<path | ||
d="M33.7678462,58.6032308 L32.8047692,42.5016923 C32.6586154,41.6278462 32.3832308,40.8032308 31.9986154,40.0463077" | ||
id="Stroke-15" | ||
strokeLinecap="round" | ||
/> | ||
<path | ||
d="M31.9986154,40.0464615 C30.5786154,37.2495385 27.6801538,35.3849231 24.4016923,35.3849231 L7.95707692,35.3849231 C5.39246154,35.3849231 3.06015385,36.5264615 1.48630769,38.3618462" | ||
id="Stroke-17" | ||
strokeLinecap="round" | ||
/> | ||
<path | ||
d="M22.5238462,35.4156923 C25.1838462,34.8603077 27.8161538,33.9572308 30.3623077,32.6849231 L30.3623077,21.6187692 C30.3623077,13.6618462 23.9115385,7.21261538 15.9561538,7.21261538 C8.00076923,7.21261538 1.55153846,13.6618462 1.55153846,21.6187692 L1.55153846,32.6849231 C3.69769231,33.7556923 6.80076923,34.8433846 9.12692308,35.4156923" | ||
id="Stroke-19" | ||
/> | ||
<path | ||
d="M6.18107692,17.8535385 C7.678,18.4735385 9.02876923,18.952 10.6195385,19.2889231 L12.0533846,15.7581538 L12.138,19.7458462 C16.2349231,20.1181538 21.898,19.4212308 25.9641538,17.7381538 L26.0103077,17.7381538 C27.0918462,19.4996923 27.7149231,21.572 27.7149231,23.7904615 C27.7149231,30.1935385 22.5241538,35.3843077 16.1210769,35.3843077 C9.718,35.3843077 4.52723077,30.1935385 4.52723077,23.7904615 C4.52723077,21.7458462 5.05646154,19.8243077 5.98569231,18.1566154 L6.18107692,17.8535385 Z" | ||
id="Stroke-21" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
<path | ||
d="M0.000153846167,29.5121538 C0.000153846167,45.8106154 13.2124615,59.0244615 29.5124615,59.0244615 C45.8109231,59.0244615 59.0247692,45.8106154 59.0247692,29.5121538" | ||
id="Stroke-23" | ||
/> | ||
<path | ||
d="M39.0553846,14.1330769 C42.1815385,18.3853846 47.8369231,20.27 53.0507692,18.3823077 C54.4338462,17.8823077 55.6723077,17.1561538 56.7369231,16.2623077" | ||
id="Stroke-25" | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
/> | ||
</g> | ||
</g> | ||
</g> | ||
</svg> | ||
); | ||
} | ||
|
||
export function Greeting(props) { | ||
let svg = <GreetingSpaceSVG />; | ||
let description = `This is a shared space between you and other group members. Here's where you'll see shared messages, files, and a call history with this space.`; | ||
|
||
if (props.personName) { | ||
svg = <GreetingDirectSVG />; | ||
description = `This is your private conversation with ${props.personName}. Here's where you'll see shared messages, files, and a call history with this person.`; | ||
} | ||
|
||
return ( | ||
<div className="greeting"> | ||
<div className="greeting-header"> | ||
{svg} | ||
<div className="greeting-description">{description}</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
Greeting.propTypes = { | ||
personName: PropTypes.string.isRequired, | ||
}; | ||
|
||
export default function WebexActivityStream(props) { | ||
const {roomID, adapter} = props; | ||
const {title, roomType} = useRoom(roomID, adapter); | ||
const activityIDs = useActivityStream(roomID, adapter); | ||
const personName = roomType === RoomType.DIRECT ? title : ''; | ||
|
||
return <div className="activity-stream">{!activityIDs.length && <Greeting personName={personName} />}</div>; | ||
} | ||
|
||
WebexActivityStream.propTypes = { | ||
roomID: PropTypes.string.isRequired, | ||
adapter: PropTypes.object.isRequired, | ||
}; |
18 changes: 18 additions & 0 deletions
18
src/components/WebexActivityStream/WebexActivityStream.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
.greeting { | ||
display: block; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
max-width: 37.5rem; | ||
text-align: center; | ||
color: $gray-dark-3; | ||
|
||
.greeting-header { | ||
@include header-fonts; | ||
} | ||
|
||
.greeting-description { | ||
@include body-fonts; | ||
padding: 0 3.125rem; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
src/components/WebexActivityStream/WebexActivityStream.stories.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import React from 'react'; | ||
import {storiesOf} from '@storybook/react'; | ||
|
||
import RoomsJSONAdapter from '../../adapters/RoomsJSONAdapter'; | ||
import {RoomType} from '../../adapters/RoomsAdapter'; | ||
import rooms from '../../data/rooms'; | ||
|
||
import WebexActivityStream from './WebexActivityStream'; | ||
|
||
// Setup for the stories | ||
const [roomID] = Object.keys(rooms); | ||
const stories = storiesOf('Webex Activity Stream', module); | ||
const newRooms = {}; | ||
|
||
// Stories | ||
stories.add('empty group stream', () => <WebexActivityStream roomID={roomID} adapter={new RoomsJSONAdapter(rooms)} />); | ||
stories.add('empty 1:1 stream', () => { | ||
newRooms[roomID] = { | ||
...rooms[roomID], | ||
roomType: RoomType.DIRECT, | ||
}; | ||
|
||
return <WebexActivityStream roomID={roomID} adapter={new RoomsJSONAdapter(newRooms)} />; | ||
}); |
64 changes: 64 additions & 0 deletions
64
src/components/WebexActivityStream/WebexActivityStream.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react'; | ||
|
||
import RoomsJSONAdapter from '../../adapters/RoomsJSONAdapter'; | ||
import {RoomType} from '../../adapters/RoomsAdapter'; | ||
import rooms from '../../data/rooms'; | ||
|
||
import WebexActivityStream, {Greeting, GreetingSpaceSVG, GreetingDirectSVG} from './WebexActivityStream'; | ||
|
||
jest.mock('../hooks/useRoom'); | ||
jest.mock('../hooks/useActivityStream'); | ||
|
||
describe('Webex Activity Stream component', () => { | ||
let roomID, newRooms, roomsAdapter; | ||
|
||
beforeEach(() => { | ||
[roomID] = Object.keys(rooms); | ||
newRooms = rooms; | ||
roomsAdapter = new RoomsJSONAdapter(rooms); | ||
}); | ||
|
||
describe('Greeting Space SVG snapshot', () => { | ||
test('matches with greeting space SVG', () => { | ||
expect(shallow(<GreetingSpaceSVG />)).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe('Greeting 1:1 SVG snapshot', () => { | ||
test('matches with greeting 1:1 SVG', () => { | ||
expect(shallow(<GreetingDirectSVG />)).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe('Greeting component snapshot', () => { | ||
test('matches with empty space', () => { | ||
expect(shallow(<Greeting personName="" />)).toMatchSnapshot(); | ||
}); | ||
|
||
test('matches with empty 1:1', () => { | ||
expect(shallow(<Greeting personName="personName" />)).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe('Webex Activity Stream snapshots', () => { | ||
test('matches with empty group stream', () => { | ||
expect(shallow(<WebexActivityStream roomID={roomID} adapter={roomsAdapter} />)).toMatchSnapshot(); | ||
}); | ||
|
||
test('matches with empty direct stream', () => { | ||
newRooms[roomID] = { | ||
...rooms[roomID], | ||
roomType: RoomType.DIRECT, | ||
}; | ||
roomsAdapter = new RoomsJSONAdapter(newRooms); | ||
|
||
expect(shallow(<WebexActivityStream roomID={roomID} adapter={roomsAdapter} />)).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
roomsAdapter = null; | ||
newRooms = null; | ||
roomID = null; | ||
}); | ||
}); |
Oops, something went wrong.