Skip to content

Commit 0bfbe08

Browse files
committed
feat(ActivityStream): add TimeRuler component
1 parent e4b899c commit 0bfbe08

File tree

5 files changed

+989
-5
lines changed

5 files changed

+989
-5
lines changed

src/components/WebexActivityStream/WebexActivityStream.js

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,44 @@
11
import React, {Fragment} from 'react';
22
import PropTypes from 'prop-types';
3+
import {ListSeparator} from '@momentum-ui/react';
4+
import {format, isToday, isSameWeek, isYesterday} from 'date-fns';
35

46
import {RoomType} from '../../adapters/RoomsAdapter';
57
import {useActivityStream, useRoom} from '../hooks';
68
import WebexActivity from '../WebexActivity/WebexActivity';
79

810
import './WebexActivityStream.scss';
911

12+
/**
13+
* Returns a formatted timestamp based on the given date's offset from the current time.
14+
*
15+
* Divisor for messages from today display today
16+
* Divisor for messages from dates from a previous day display as Yesterday
17+
* Divisor for messages of dates from a previous day of the week (but not yesterday) display as <day of the week>
18+
* Divisor for messages of dates older than a week from today display as M/D/YY
19+
*
20+
* @param {Date} timestamp Date instance to format
21+
* @returns {string} formattedDate
22+
*/
23+
export function formatTimeRulerText(timestamp) {
24+
let formattedDate;
25+
26+
if (isToday(timestamp)) {
27+
formattedDate = 'today';
28+
} else if (isYesterday(timestamp)) {
29+
// Yesterday
30+
formattedDate = 'Yesterday';
31+
} else if (isSameWeek(timestamp, new Date())) {
32+
// Monday
33+
formattedDate = format(timestamp, 'iiii');
34+
} else {
35+
// 1/1/2020
36+
formattedDate = format(timestamp, 'P');
37+
}
38+
39+
return formattedDate;
40+
}
41+
1042
export function GreetingDirectSVG() {
1143
return (
1244
<svg
@@ -138,19 +170,34 @@ Greeting.propTypes = {
138170
personName: PropTypes.string.isRequired,
139171
};
140172

173+
export function TimeRuler({text}) {
174+
return <ListSeparator className="time-ruler" role="listitem" text={text} />;
175+
}
176+
177+
TimeRuler.propTypes = {
178+
text: PropTypes.string.isRequired,
179+
};
180+
141181
export default function WebexActivityStream(props) {
142182
const {roomID, adapters} = props;
143183
const {roomsAdapter, activitiesAdapter, peopleAdapter} = adapters;
144184
const {title, roomType} = useRoom(roomID, roomsAdapter);
145-
const activityIDs = useActivityStream(roomID, roomsAdapter);
185+
const activitiesData = useActivityStream(roomID, roomsAdapter);
146186
const personName = roomType === RoomType.DIRECT ? title : '';
147-
const activities = activityIDs.map((activityID) => (
148-
<WebexActivity key={activityID} activityID={activityID} adapters={{activitiesAdapter, peopleAdapter}} />
149-
));
187+
const activities = activitiesData.map((activity) => {
188+
// If the activity is an object with a date property, it is a time ruler
189+
const activityComponent = activity.date ? (
190+
<TimeRuler key={activity.date.toString()} text={formatTimeRulerText(new Date(activity.date))} />
191+
) : (
192+
<WebexActivity key={activity} activityID={activity} adapters={{activitiesAdapter, peopleAdapter}} />
193+
);
194+
195+
return activityComponent;
196+
});
150197

151198
return (
152199
<div className="activity-stream">
153-
{activityIDs.length ? <Fragment>{activities}</Fragment> : <Greeting personName={personName} />}
200+
{activities.length ? <Fragment>{activities}</Fragment> : <Greeting personName={personName} />}
154201
</div>
155202
);
156203
}

src/components/WebexActivityStream/WebexActivityStream.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@
1616
padding: 0 3.125rem;
1717
}
1818
}
19+
20+
.time-ruler {
21+
padding: 0 3rem;
22+
}

src/components/WebexActivityStream/WebexActivityStream.stories.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ stories.add('default', () => <WebexActivityStream roomID="default" adapters={ada
2020
stories.add('empty group stream', () => <WebexActivityStream roomID="empty-space" adapters={adapters} />);
2121

2222
stories.add('empty 1:1 stream', () => <WebexActivityStream roomID="empty-direct" adapters={adapters} />);
23+
24+
stories.add('with time rulers', () => <WebexActivityStream roomID="time-rulers" adapters={adapters} />);

src/components/WebexActivityStream/WebexActivityStream.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ describe('Webex Activity Stream component', () => {
5252
test('matches with empty direct stream', () => {
5353
expect(shallow(<WebexActivityStream roomID="empty-direct" adapters={adapters} />)).toMatchSnapshot();
5454
});
55+
56+
test('matches with time rulers stream', () => {
57+
expect(shallow(<WebexActivityStream roomID="time-rulers" adapters={adapters} />)).toMatchSnapshot();
58+
});
5559
});
5660

5761
afterEach(() => {

0 commit comments

Comments
 (0)