Skip to content
This repository was archived by the owner on Nov 13, 2024. It is now read-only.

Commit 87586da

Browse files
author
Jeff Moore
committed
Releasing v0.8.0
1 parent 0ec72b9 commit 87586da

File tree

109 files changed

+15376
-4056
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

109 files changed

+15376
-4056
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

33
# dependencies
4-
/node_modules
4+
node_modules
55
/.pnp
66
.pnp.js
77

README.md

+28-6
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,6 @@ The application demonstrates how to build a chat application using:
1313
- React
1414
- Redux
1515

16-
## Tutorial
17-
We've put together a comprehensive tutorial that explains how key features are built in the team chat app. With this tutorial, you should have a better understanding of of our underlying React and Redux frameworks and the Javascript SDK. You can use these frameworks & SDKs to easily add chat capabilities to any application.
18-
19-
[Click here](https://www.pubnub.com/blog/build-a-fully-featured-react-chat-app/) to view the tutorial.
20-
2116
## Requirements
2217

2318
- [Node.js](https://nodejs.org/en/)
@@ -64,8 +59,35 @@ To run this application you must obtain publish and subscribe keys from your Pub
6459

6560
A web browser should automatically open [http://localhost:3000](http://localhost:3000), and you can explore your very own Team Chat app!
6661

62+
## Documentation
63+
64+
We've included additional documentation and a detailed tutorial for building a chat app with React, Redux, and PubNub.
65+
You can view it in the `/docs` directory or run the documentation site locally.
66+
67+
### Running the docs website
68+
69+
1. If you haven't already, clone the GitHub repository
70+
71+
```bash
72+
git clone git@github.com:pubnub/typescript-ref-app-team-chat.git
73+
```
74+
75+
1. Install the dependencies
76+
77+
```bash
78+
cd typescript-ref-app-team-chat/website
79+
npm install
80+
```
81+
82+
1. Run the docs website locally.
83+
84+
```bash
85+
npm start
86+
```
87+
If the chat app is already running, you may be asked to accept a different port. Your browser should open to [http//localhost:3000](http://localhost:3000) where you can find the tutorial and docs.
88+
6789
## Further Information
6890

69-
Checkout the comprehensive [Tutorial](https://www.pubnub.com/blog/build-a-fully-featured-react-chat-app/) or visit the [PubNub Chat Docs](https://www.pubnub.com/docs/chat) page for more information about how to use the React and Redux SDKs to add in-app chat to your applications.
91+
Checkout [PubNub Chat Docs](https://www.pubnub.com/docs/chat) page for more information about how to use the React and Redux SDKs to add in-app chat to your applications.
7092

7193
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). Special thanks to Martin Lagrange, Elvis Wolcott, and Mark Erikson.

docs/quickstart/frameworks.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
id: frameworks
3+
title: Frameworks
4+
sidebar_label: Frameworks
5+
---
6+
7+
## React
8+
9+
Our React framework provides tools to leverage the PubNub JavaScript SDK within a React application by making use of React features like Provider and Consumer patterns and React Hooks.
10+
11+
[View reference docs](https://www.pubnub.com/docs/chat/react/setup).
12+
13+
## Redux
14+
15+
Our Redux framework makes it easier for you to manage the state of data components inside an application.
16+
The framework adds structured data to the Redux store, listens to realtime events generated by the network, stores these events on the client side, and triggers updates to the view inside your application.
17+
These Redux-specific functions can be integrated with your existing or new Redux data store.
18+
19+
[View reference docs](https://www.pubnub.com/docs/chat/redux/setup).
20+
21+
## Javascript
22+
23+
Our React and Redux frameworks have a dependency on the Javascript SDK to manage connections and communicate with the PubNub network.
24+
25+
[View reference docs](https://www.pubnub.com/docs/chat/reference/setup).

docs/quickstart/introduction.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
id: introduction
3+
title: Introduction
4+
sidebar_label: Introduction
5+
---
6+
7+
Team Chat is our group chat app with features like user login, joining/leaving group conversations, send/receive messages, members online/offline presence, typing indicators, profanity filtering and more. Its UI is built in React, and uses the PubNub Redux framework to manage client state on the application.
8+
9+
![team chat preview](/img/team-chat-preview.png)
10+
11+
## Features
12+
13+
- [Theming](/docs/tutorial/theming) to quickly customize the look and branding of your application
14+
- [Messaging](/docs/tutorial/messages) powered by PubNub
15+
- [Join](/docs/tutorial/join-conversation) and [Leave](/docs/tutorial/leave-conversation) conversations
16+
- [Conversation Members](/docs/tutorial-conversation-members) including online/offline status using Presence
17+
- [Typing Indicators](/docs/tutorial/typing-indicators) let users know when another user is typing
18+
- [Profanity Filtering](/docs/profanity-filtering) to moderate messages with serverless PubNub functions
19+
20+
## Add more features
21+
22+
Visit the [React](https://pubnub.com/docs/chat/frameworks/react) and [Redux](https://pubnub.com/docs/chat/frameworks/redux) reference docs to add more features to your app like unread message counts, read receipts, reactions, and more.
23+
24+
## Resources
25+
26+
- [Chat Docs](https://www.pubnub.com/docs/chat/quickstart)
27+
- [PubNub Chat](https://www.pubnub.com/products/pubnub-chat/)

docs/quickstart/run-locally.md

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
id: run-locally
3+
title: Running the App
4+
sidebar_label: Run Locally
5+
---
6+
7+
Follow the instructions below to run the app in your local environment.
8+
9+
## Requirements
10+
11+
- [Node.js](https://nodejs.org/en/)
12+
- [PubNub Account](#pubnub-account) (*Free*)
13+
14+
### PubNub Account
15+
16+
To run this application you must obtain publish and subscribe keys from your PubNub Account. If you don't already have an account, you can [create one for free](https://dashboard.pubnub.com/).
17+
18+
1. Sign in to your [PubNub Dashboard](https://dashboard.pubnub.com/).
19+
20+
1. Click **Create New App**.
21+
22+
1. Give your app a name, and select **Chat App** as the app type.
23+
24+
1. Select a region to store your user data (e.g. *Portland*).
25+
26+
1. Click **Create**.
27+
28+
1. Click your new app to open its settings, then click its keyset.
29+
30+
1. Locate the *Publish* and *Subscribe* keys. You'll need these keys to include in this project.
31+
32+
## Running the project
33+
34+
1. Clone the GitHub repository.
35+
36+
```bash
37+
git clone git@github.com:pubnub/typescript-ref-app-team-chat.git
38+
```
39+
40+
1. Install the project.
41+
42+
```bash
43+
cd typescript-ref-app-team-chat
44+
npm install
45+
```
46+
47+
1. Run the project in your local environment. If you are running the app for the first time, enter your PubNub keys to begin populating sample data.
48+
49+
```bash
50+
npm start
51+
```
52+
53+
A web browser should automatically open [http://localhost:3000](http://localhost:3000), and you can explore your very own Team Chat app!

docs/tutorial/conversation-members.md

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
---
2+
id: conversation-members
3+
title: Show Members in Conversation
4+
sidebar_label: Conversation Members
5+
---
6+
7+
Click the membership count at the top right of a conversation, and you’ll see the conversation’s member list.
8+
Online members are placed at the top of the list and have a green dot, while offline members are below, and greyed out.
9+
10+
![members list](/img/team-chat-member-list.png)
11+
12+
The `conversationMembers/ConversationMembers/ConversationMembers.tsx` component displays the list of members that belong to the conversations.
13+
It calls the [fetchMembers](https://www.pubnub.com/docs/chat/redux/members#fetchmembers) command to get the list of members in the conversation from PubNub and stores the members in the local store.
14+
15+
The component also calls the [fetchHereNow](https://www.pubnub.com/docs/chat/redux/presence#fetchherenow) command from the Redux framework.
16+
This command uses presence to indicate if members in the conversation are online.
17+
[Presence](https://www.pubnub.com/docs/chat/redux/presence) allows you to track the state of users in realtime.
18+
When users are connected to the app and present in the conversation, their "present" state is indicated with a green dot.
19+
If they are away from the app, their "away" state is indicated by removing the green dot and graying out their name.
20+
21+
```tsx
22+
export const getCurrentConversationMembers = createSelector(
23+
[
24+
getUsersById,
25+
getCurrentConversationId,
26+
getUsersByConversationId,
27+
getPresenceByConversationId
28+
],
29+
(
30+
users: UsersIndexedById,
31+
conversationId: string,
32+
conversationMemberships: MembershipHash,
33+
conversationPresence: ConversationPresence
34+
): UserFragment[] => {
35+
let presence = conversationPresence[conversationId];
36+
return conversationMemberships[conversationId]
37+
? conversationMemberships[conversationId].map(user => {
38+
return {
39+
...users[user.id],
40+
presence: presence
41+
? presence.occupants.filter(occupant => {
42+
return occupant.uuid === user.id;
43+
}).length > 0
44+
: false
45+
};
46+
})
47+
: [];
48+
}
49+
);
50+
const orderByPresence = (members: UserFragment[]) => {
51+
return members.sort((userA, userB) =>
52+
userA.presence === userB.presence ? 0 : userA.presence ? -1 : 1
53+
);
54+
};
55+
const ConversationMembers = () => {
56+
const members: UserFragment[] = useSelector(getCurrentConversationMembers);
57+
const currentConversationId = useSelector(getCurrentConversationId);
58+
const dispatch = useDispatch();
59+
const pubnub = usePubNub();
60+
const views = useSelector(getViewStates);
61+
const themeContext = useContext(ThemeContext);
62+
const isSmall = useMediaQuery(themeContext.breakpoint.mediaQuery.small);
63+
useEffect(() => {
64+
if (members.length === 0) {
65+
dispatch(
66+
fetchMembers({
67+
spaceId: currentConversationId,
68+
include: {
69+
userFields: true,
70+
customUserFields: true,
71+
totalCount: false
72+
}
73+
})
74+
);
75+
dispatch(
76+
fetchHereNow({
77+
channels: [currentConversationId]
78+
})
79+
);
80+
}
81+
}, [members, currentConversationId, pubnub, dispatch]);
82+
return (
83+
<Wrapper
84+
animate={views.ConversationMembers ? "open" : "closed"}
85+
variants={getAnimatedWrapperVariants(isSmall)}
86+
>
87+
<Header>
88+
<Title>
89+
<BackIconWrapper
90+
onClick={() => {
91+
dispatch(conversationMembersViewHidden());
92+
}}
93+
>
94+
<BackIcon title="back" />
95+
</BackIconWrapper>
96+
Members
97+
</Title>
98+
<CloseIcon
99+
onClick={() => {
100+
dispatch(conversationMembersViewHidden());
101+
}}
102+
>
103+
<CrossIcon title="close members list" />
104+
</CloseIcon>
105+
</Header>
106+
<ScrollableView>
107+
{orderByPresence(members).map(user => (
108+
<MemberDescription user={user} key={user.id} />
109+
))}
110+
</ScrollableView>
111+
</Wrapper>
112+
);
113+
};
114+
export { ConversationMembers };
115+
```
116+
117+
## Member Details
118+
119+
The `MemberDescription` method (in `conversationMembers/MemberDescription/MemberDescription.tsx`) displays the name, profile image, and title of each member.
120+
121+
The member list also displays user presence to indicate if users are online or offline within a conversation.
122+
The app fetches the presence state from the `user.presence` flag in the [local](https://www.pubnub.com/docs/chat/redux/presence#state-shape) store.
123+
The next section provides more details on presence events.
124+
125+
```tsx
126+
const MemberDescription = ({ user }: MemberDescriptionProps) => {
127+
return (
128+
<Wrapper>
129+
<Avatar>
130+
<UserInitialsAvatar
131+
size={36}
132+
name={user.name}
133+
userId={user.id}
134+
muted={!user.presence}
135+
/>
136+
</Avatar>
137+
<About>
138+
<UserName muted={!user.presence}>
139+
{user.name}{" "}
140+
{user.presence && <PresenceDot presence={user.presence} />}
141+
</UserName>
142+
<UserTitle muted={!user.presence}>{user.custom.title}</UserTitle>
143+
</About>
144+
</Wrapper>
145+
);
146+
};
147+
export { MemberDescription };
148+
```
149+
150+
## Presence Events
151+
152+
The `features/memberPresence/memberPresenceModel.ts` file calls [createPresenceReducer()](https://www.pubnub.com/docs/chat/redux/presence#createpresencereducer) reducer from the Redux framework.
153+
This automatically updates the presence state for users in the local store.
154+
The reducer responds to actions that are dispatched when presence join, leave, timeout or interval events are received by the app.
155+
156+
```tsx
157+
/**
158+
* Create a reducer to presence information for conversation members
159+
*/
160+
const MemberPresenceReducer = createPresenceReducer();
161+
export { MemberPresenceReducer };
162+
```
163+
164+
## Presence Occupancy
165+
The `currentConversation/ConversationOccupancy/ConversationOccupancy.tsx` component uses `joinedCount` and `presentCount` to show counts of all members in the conversation and the count of members who are currently online.
166+
167+
The component uses the `getUsersByConversationId` selector to get all members from the [local store](https://www.pubnub.com/docs/chat/redux/presence#state-shape) and `getPresenceByConversationId` to get online users from the [local store](https://www.pubnub.com/docs/chat/redux/presence#state-shape).
168+
169+
```tsx
170+
export interface ConversationOccupancyFragment {
171+
joinedCount: number;
172+
presentCount: number;
173+
}
174+
export const getCurrentConversationOccupancy = createSelector(
175+
[
176+
getCurrentConversationId,
177+
getUsersByConversationId,
178+
getPresenceByConversationId
179+
],
180+
(
181+
currentConversationId: string,
182+
conversationMemberships: MembershipHash,
183+
conversationPresence: ConversationPresence
184+
): ConversationOccupancyFragment => {
185+
const members = conversationMemberships[currentConversationId];
186+
const presence = conversationPresence[currentConversationId];
187+
return {
188+
joinedCount: members ? members.length : 0,
189+
presentCount: presence ? presence.occupancy : 0
190+
};
191+
}
192+
);
193+
const ConversationOccupancy = () => {
194+
const {
195+
joinedCount,
196+
presentCount
197+
}: ConversationOccupancyFragment = useSelector(
198+
getCurrentConversationOccupancy
199+
);
200+
const views = useSelector(getViewStates);
201+
const isConversationMembersLayoutVisible = views.ConversationMembers;
202+
const dispatch = useDispatch();
203+
return (
204+
<Wrapper
205+
highlighted={isConversationMembersLayoutVisible}
206+
onClick={() => {
207+
isConversationMembersLayoutVisible
208+
? dispatch(conversationMembersViewHidden())
209+
: dispatch(conversationMembersViewDisplayed());
210+
}}
211+
>
212+
<OccupancyNumber>
213+
<em>{presentCount}</em> | {joinedCount}
214+
</OccupancyNumber>
215+
<IconWrapper>
216+
<PeopleGroupIcon
217+
title={
218+
isConversationMembersLayoutVisible
219+
? "Hide members list"
220+
: "Show conversation members"
221+
}
222+
active={isConversationMembersLayoutVisible}
223+
/>
224+
</IconWrapper>
225+
</Wrapper>
226+
);
227+
};
228+
229+
export { ConversationOccupancy };
230+
```

0 commit comments

Comments
 (0)