This repository has been archived by the owner on Apr 22, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create and retrieve messages through RoomChannel
- Loading branch information
Showing
15 changed files
with
346 additions
and
9 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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,3 +1,4 @@ | |||
defmodule Sling.Repo do | defmodule Sling.Repo do | ||
use Ecto.Repo, otp_app: :sling | use Ecto.Repo, otp_app: :sling | ||
use Scrivener, page_size: 25 | |||
end | end |
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
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
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
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,15 @@ | |||
defmodule Sling.MessageView do | |||
use Sling.Web, :view | |||
|
|||
def render("message.json", %{message: message}) do | |||
%{ | |||
id: message.id, | |||
inserted_at: message.inserted_at, | |||
text: message.text, | |||
user: %{ | |||
email: message.user.email, | |||
username: message.user.username | |||
} | |||
} | |||
end | |||
end |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,10 @@ | |||
defmodule Sling.PaginationHelpers do | |||
def pagination(page) do | |||
%{ | |||
page_number: page.page_number, | |||
page_size: page.page_size, | |||
total_pages: page.total_pages, | |||
total_entries: page.total_entries | |||
} | |||
end | |||
end |
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
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
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,24 @@ | |||
// @flow | |||
import React from 'react'; | |||
import md5 from 'md5'; | |||
|
|||
type Props = { | |||
email: string, | |||
size?: number, | |||
style?: Object, | |||
} | |||
|
|||
const Avatar = ({ email, size = 40, style }: Props) => { | |||
const hash = md5(email); | |||
const uri = `https://secure.gravatar.com/avatar/${hash}`; | |||
|
|||
return ( | |||
<img | |||
src={uri} | |||
alt={email} | |||
style={{ width: `${size}px`, height: `${size}px`, borderRadius: '4px', ...style }} | |||
/> | |||
); | |||
}; | |||
|
|||
export default Avatar; |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,29 @@ | |||
// @flow | |||
import React from 'react'; | |||
import moment from 'moment'; | |||
import Avatar from '../Avatar'; | |||
|
|||
type Props = { | |||
message: { | |||
text: string, | |||
inserted_at: string, | |||
user: { | |||
email: string, | |||
username: string, | |||
}, | |||
} | |||
} | |||
|
|||
const Message = ({ message: { text, inserted_at, user } }: Props) => | |||
<div style={{ display: 'flex', marginBottom: '10px' }}> | |||
<Avatar email={user.email} style={{ marginRight: '10px' }} /> | |||
<div> | |||
<div style={{ lineHeight: '1.2' }}> | |||
<b style={{ marginRight: '8px', fontSize: '14px' }}>{user.username}</b> | |||
<time style={{ fontSize: '12px', color: 'rgb(192,192,192)' }}>{moment(inserted_at).format('h:mm A')}</time> | |||
</div> | |||
<div>{text}</div> | |||
</div> | |||
</div>; | |||
|
|||
export default Message; |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,73 @@ | |||
// @flow | |||
import React, { Component } from 'react'; | |||
import { Field, reduxForm } from 'redux-form'; | |||
import { css, StyleSheet } from 'aphrodite'; | |||
|
|||
const styles = StyleSheet.create({ | |||
form: { | |||
padding: '0px 10px 10px 10px', | |||
background: '#fff', | |||
}, | |||
|
|||
input: { | |||
borderWidth: '2px', | |||
borderColor: 'rgb(214,214,214)', | |||
}, | |||
|
|||
button: { | |||
color: 'rgb(80,80,80)', | |||
background: 'rgb(214,214,214)', | |||
borderWidth: '2px', | |||
borderColor: 'rgb(214,214,214)', | |||
}, | |||
}); | |||
|
|||
type Props = { | |||
onSubmit: () => void, | |||
handleSubmit: () => void, | |||
submitting: boolean, | |||
} | |||
|
|||
class MessageForm extends Component { | |||
props: Props | |||
|
|||
handleSubmit = data => this.props.onSubmit(data); | |||
|
|||
render() { | |||
const { handleSubmit, submitting } = this.props; | |||
|
|||
return ( | |||
<form onSubmit={handleSubmit(this.handleSubmit)} className={css(styles.form)}> | |||
<div className="input-group"> | |||
<Field | |||
name="text" | |||
type="text" | |||
component="input" | |||
className={`form-control ${css(styles.input)}`} | |||
/> | |||
<div className="input-group-btn"> | |||
<button | |||
disabled={submitting} | |||
className={`btn ${css(styles.button)}`} | |||
> | |||
Send | |||
</button> | |||
</div> | |||
</div> | |||
</form> | |||
); | |||
} | |||
} | |||
|
|||
const validate = (values) => { | |||
const errors = {}; | |||
if (!values.text) { | |||
errors.text = 'Required'; | |||
} | |||
return errors; | |||
}; | |||
|
|||
export default reduxForm({ | |||
form: 'newMessage', | |||
validate, | |||
})(MessageForm); |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,88 @@ | |||
// @flow | |||
import React, { Component } from 'react'; | |||
import moment from 'moment'; | |||
import groupBy from 'lodash/groupBy'; | |||
import mapKeys from 'lodash/mapKeys'; | |||
import { css, StyleSheet } from 'aphrodite'; | |||
import Message from '../Message'; | |||
|
|||
const styles = StyleSheet.create({ | |||
container: { | |||
flex: '1', | |||
padding: '10px 10px 0 10px', | |||
background: '#fff', | |||
overflowY: 'auto', | |||
}, | |||
|
|||
dayDivider: { | |||
position: 'relative', | |||
margin: '1rem 0', | |||
textAlign: 'center', | |||
'::after': { | |||
position: 'absolute', | |||
top: '50%', | |||
right: '0', | |||
left: '0', | |||
height: '1px', | |||
background: 'rgb(240,240,240)', | |||
content: '""', | |||
}, | |||
}, | |||
|
|||
dayText: { | |||
zIndex: '1', | |||
position: 'relative', | |||
background: '#fff', | |||
padding: '0 12px', | |||
}, | |||
}); | |||
|
|||
type MessageType = { | |||
id: number, | |||
inserted_at: string, | |||
} | |||
|
|||
type Props = { | |||
messages: Array<MessageType>, | |||
} | |||
|
|||
class MessageList extends Component { | |||
props: Props | |||
|
|||
renderMessages = messages => | |||
messages.map(message => <Message key={message.id} message={message} />); | |||
|
|||
renderDays() { | |||
const { messages } = this.props; | |||
messages.map(message => message.day = moment(message.inserted_at).format('MMMM Do')); // eslint-disable-line | |||
const dayGroups = groupBy(messages, 'day'); | |||
const days = []; | |||
mapKeys(dayGroups, (value, key) => { | |||
days.push({ date: key, messages: value }); | |||
}); | |||
const today = moment().format('MMMM Do'); | |||
const yesterday = moment().subtract(1, 'days').format('MMMM Do'); | |||
return days.map(day => | |||
<div key={day.date}> | |||
<div className={css(styles.dayDivider)}> | |||
<span className={css(styles.dayText)}> | |||
{day.date === today && 'Today'} | |||
{day.date === yesterday && 'Yesterday'} | |||
{![today, yesterday].includes(day.date) && day.date} | |||
</span> | |||
</div> | |||
{this.renderMessages(day.messages)} | |||
</div> | |||
); | |||
} | |||
|
|||
render() { | |||
return ( | |||
<div className={css(styles.container)}> | |||
{this.renderDays()} | |||
</div> | |||
); | |||
} | |||
} | |||
|
|||
export default MessageList; |
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 | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,24 @@ | |||
// @flow | |||
import React from 'react'; | |||
import { css, StyleSheet } from 'aphrodite'; | |||
|
|||
const styles = StyleSheet.create({ | |||
navbar: { | |||
padding: '15px', | |||
background: '#fff', | |||
borderBottom: '1px solid rgb(240,240,240)', | |||
}, | |||
}); | |||
|
|||
type Props = { | |||
room: { | |||
name: string, | |||
}, | |||
} | |||
|
|||
const RoomNavbar = ({ room }: Props) => | |||
<nav className={css(styles.navbar)}> | |||
<div>#{room.name}</div> | |||
</nav>; | |||
|
|||
export default RoomNavbar; |
Oops, something went wrong.