Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connected user list #40

Merged
merged 31 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ab81f5e
emit peer disconnected event
santakadev Mar 27, 2019
46ef685
add peer set
santakadev Mar 27, 2019
f033389
add peer list component
santakadev Mar 31, 2019
4597ce5
reactive arquitecture
santakadev Apr 14, 2019
daf82ff
show hypercore id of connected peer
santakadev Apr 15, 2019
f8ef3f7
show display name
santakadev Apr 19, 2019
0b8a0b3
update style
santakadev Apr 19, 2019
9a942a1
use random name
santakadev Apr 19, 2019
1d1bb24
setup redux
santakadev Apr 30, 2019
1b12722
connect peers actions with redux
santakadev May 1, 2019
a3e9e8c
refactor: use react/redux for user list component
santakadev May 2, 2019
dc3e545
refactor: extract redux reducer to its own file
santakadev May 2, 2019
0641651
move state to redux store
santakadev May 6, 2019
20ec656
use redux middleware to store actions that need to be notified in hyp…
santakadev May 6, 2019
c5673f7
set display name when starting/joining a session
santakadev May 7, 2019
8e05ce0
fix eslint warms
santakadev May 30, 2019
b9aa2ac
add style to display name input
santakadev May 30, 2019
cf72bdf
use HTML forms for start and join session
santakadev May 30, 2019
45bd162
refactor: extract to a module notifyPeers redux middleware
santakadev Jun 1, 2019
2f0fa5f
add user disconnected redux action
santakadev Jun 1, 2019
c81bcc7
make home page full width in mobile
santakadev Jun 3, 2019
2b41317
add current user to connected user list
santakadev Jun 3, 2019
d3cfb31
add title to user list component
santakadev Jun 4, 2019
2a8d4f2
add close button to user list panel
santakadev Jun 4, 2019
ba20565
add close button to user list panel
santakadev Jun 4, 2019
1668a54
add scroll to user list
santakadev Jun 4, 2019
1e0377c
add right menu
santakadev Jun 4, 2019
b560928
show user count
santakadev Jun 4, 2019
4756150
add menu component
santakadev Jun 5, 2019
4989f6f
add reactive swarm
santakadev Jun 6, 2019
0a01274
fix typo
santakadev Jun 6, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"dotenv-webpack": "^1.7.0",
"hypercore": "^6.24.0",
"random-access-memory": "^3.1.1",
"react-redux": "^7.0.3",
"redux": "^4.0.1",
"redux-devtools-extension": "^2.13.8",
"signalhub": "^4.9.0",
"webpack-dev-server": "^3.1.14",
"webrtc-swarm": "^2.9.0"
Expand Down
96 changes: 93 additions & 3 deletions public/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
left: 0;
right: 0;
bottom: 0;
z-index: 5;
z-index: 6;
background: #202020;
color: #fff;
}
Expand All @@ -43,6 +43,8 @@

.start-new-session,
.join-session {
display: flex;
flex-direction: column;
font-family: 'Roboto Mono', monospace;
padding: 15px
}
Expand All @@ -58,6 +60,11 @@
line-height: 1;
}

.start-new-session__display-name,
.join-session__display-name {
padding: 10px;
}

.start-new-session__button,
.join-session__button {
font-family: 'Roboto Mono', monospace;
Expand All @@ -69,6 +76,7 @@
border-radius: 3px;
padding: 10px 20px;
cursor: pointer;
margin-top: 5px;
}

.start-new-session__button:hover,
Expand All @@ -77,12 +85,94 @@
}

@media (max-width: 767px) {
.home-page {
width: 100%;
}

.start-new-session__button,
.join-session__button {
position: fixed;
bottom: 10;
left: 10;
bottom: 10px;
left: 10px;
height: 65px;
width: calc(100vw - 20px);
}
}

.user-list {
position: fixed;
top: 0;
right: -226px;
bottom: 0;
z-index: 5;
margin: 0;
padding: 0;
width: 225px;
font-family: 'Roboto Mono', monospace;
background: hsla(75, 9%, 31%, 1);
border-left: 1px solid hsla(75, 9%, 50%, 1);
color: hsla(70, 3%, 72%, 1);
-webkit-transition-duration: 0.3s;
-moz-transition-duration: 0.3s;
-o-transition-duration: 0.3s;
transition-duration: 0.3s;
}

.user-list--active {
right: 0;
}

.user-list__close-btn {
font-size: 28px;
position: absolute;
right: 10px;
color: hsla(70, 3%, 83%, 1);
cursor: pointer;
}

.user-list__title {
margin: 10px 8px;
color: hsla(70, 3%, 83%, 1);
font-size: 20px;
}

.user-list__container {
margin: 0;
padding: 0;
overflow-y: auto;
max-height: calc(100vh - 46px);
font-size: 14px;
}

.user-list-item {
list-style: none;
padding: 4px 10px;
}

.menu {
position: fixed;
top: 0;
right: 0;
bottom: 0;
z-index: 5;
margin: 0;
padding: 0;
width: 30px;
background: hsla(75, 9%, 31%, 1);
border-left: 1px solid hsla(75, 9%, 50%, 1);
color: hsla(70, 3%, 72%, 1);
}

.menu__item {
-webkit-transform: rotate(90.0deg);
-moz-transform: rotate(90.0deg);
-ms-transform: rotate(90.0deg);
-o-transform: rotate(90.0deg);
transform: rotate(90.0deg);
padding-left: 18px;
font-size: 12px;
font-family: 'Roboto Mono', monospace;
white-space: nowrap;
color: hsla(70, 3%, 83%, 1);
cursor: pointer;
}
36 changes: 36 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export function initializeSession(userId, sessionId, isFollower) {
return {
type: 'INITIALIZE_SESSION',
userId,
sessionId,
isFollower
}
}

export function userConnected(userId) {
return {
type: 'USER_CONNECTED',
userId
}
}

export function userDisconnected(userId) {
return {
type: 'USER_DISCONNECTED',
userId
}
}

export function startSession() {
return {
type: 'START_SESSION'
}
}

export function setDisplayName(userId, displayName) {
return {
type: 'SET_DISPLAY_NAME',
userId: userId,
displayName: displayName
}
}
3 changes: 1 addition & 2 deletions src/change-log.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ class ChangeLog extends EventEmitter {
}

replicate(peer, options) {
const stream = this.log.replicate(options)
peer.pipe(stream).pipe(peer)
return this.log.replicate(options)
}
}

Expand Down
114 changes: 83 additions & 31 deletions src/components/AppComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,100 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import HomePageComponent from './HomePageComponent';
import UserListComponent from './user-list/UserListComponent'
import { setDisplayName, startSession } from '../actions'
import MenuComponent from "./menu/MenuComponent";
import MenuItemComponent from "./menu/MenuItemComponent";

class AppComponent extends Component {

constructor(props) {
super(props)
constructor(props) {
super(props)
this.startSession = this.startSession.bind(this);

this.startSession = this.startSession.bind(this);
this.state = {
userPanelActive: true
}
}

render() {
const {sessionId, isFollower, isSessionStarted} = this.props
const {userPanelActive} = this.state

this.state = {
sessionId: props.sessionId,
isFollower: props.isFollower,
isSessionStarted: false
return (
<div>
{!isSessionStarted &&
<HomePageComponent
userId={this.props.userId}
sessionId={sessionId}
isFollower={isFollower}
onStartSession={(displayName) => this.startSession(displayName)}
/>
}
}
<MenuComponent>
<MenuItemComponent
label={`Users (${this.props.users.length})`}
onItemClicked={() => this.openUserPanel()}
/>
</MenuComponent>
<UserListComponent
users={this.props.users}
active={userPanelActive}
onCloseClicked={() => {this.closeUserPanel()}}
/>
</div>
)
}

render() {
const {sessionId, isFollower, isSessionStarted} = this.state

return (
<div>
{!isSessionStarted &&
<HomePageComponent
sessionId={sessionId}
isFollower={isFollower}
onStartSession={this.startSession}
/>
}
</div>
)
}
startSession(displayName) {
this.props.onStartSession(this.props.userId, displayName)
}

startSession() {
this.setState(state => ({
state,
isSessionStarted: true
}))
}
openUserPanel() {
this.setState((state) => ({
...state,
userPanelActive: true
}))
}

closeUserPanel() {
this.setState((state) => ({
...state,
userPanelActive: false
}))
}
}

AppComponent.propTypes = {
userId: PropTypes.string,
users: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
displayName: PropTypes.string
})),
sessionId: PropTypes.string,
isFollower: PropTypes.bool.isRequired,
isSessionStarted: PropTypes.bool,
isFollower: PropTypes.bool,
onStartSession: PropTypes.func.isRequired
}

const mapStateToProps = (state) => {
return {
userId: state.userId,
sessionId: state.sessionId,
isSessionStarted: state.isSessionStarted,
isFollower: state.isFollower,
users: state.users
}
}

const mapDispatchToProps = (dispatch) => {
return {
onStartSession: (userId, displayName) => {
dispatch(startSession())
dispatch(setDisplayName(userId, displayName))
}
}
}

export default AppComponent
export default connect(mapStateToProps, mapDispatchToProps)(AppComponent)
2 changes: 1 addition & 1 deletion src/components/HomePageComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const HomePageComponent = ({isFollower, sessionId, onStartSession}) => (

HomePageComponent.propTypes = {
sessionId: PropTypes.string,
isFollower: PropTypes.bool.isRequired,
isFollower: PropTypes.bool,
onStartSession: PropTypes.func.isRequired
}

Expand Down
57 changes: 49 additions & 8 deletions src/components/JoinSessionComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,56 @@
import React from 'react'
import React, { Component } from 'react'
import PropTypes from 'prop-types'

const JoinSessionComponent = ({sessionId, onJoinSession}) => (
<div className="join-session">
<p className="join-session__description">
class JoinSessionComponent extends Component {

constructor(props) {
super(props)

this.state = {
displayName: ''
}
}

render() {
const { sessionId } = this.props

return (
<form className="join-session" onSubmit={(e) => this.onJoinSessionSubmit(e) }>
<p className="join-session__description">
You are joining the session<br/>
<span className="join-session__session-id">{sessionId}</span>
</p>
<button className="join-session__button" onClick={onJoinSession}>Join session</button>
</div>
)
</p>
<input
className="join-session__display-name"
type="text"
placeholder="Display name"
required
onKeyUp={(e) => this.onDisplayNameChanged(e)}
/>
<button className="join-session__button">Join session</button>
</form>
)
}

onDisplayNameChanged(e) {
const displayName = e.target.value

this.setState((prevState) => ({
...prevState,
displayName
}))
}

onJoinSessionSubmit(e) {
e.preventDefault();

if (this.state.displayName === '') {
return;
}

this.props.onJoinSession(this.state.displayName)
}
}

JoinSessionComponent.propTypes = {
sessionId: PropTypes.string,
Expand Down
Loading