Skip to content

Commit

Permalink
Add connected user list (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
santakadev committed Jun 13, 2019
1 parent 9f93b44 commit f0abeb3
Show file tree
Hide file tree
Showing 20 changed files with 639 additions and 77 deletions.
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

0 comments on commit f0abeb3

Please sign in to comment.