-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
496 additions
and
5 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
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import {THREADS_STATUS_MEETHOD} from '../constants/api'; | ||
import {STATUS_FETCH, STATUS_FETCH_SUCCESS, STATUS_FETCH_FAIL} from '../constants/status'; | ||
|
||
export const fetchStatus = (folder) => ({ | ||
api: THREADS_STATUS_MEETHOD, | ||
data: { | ||
folder: folder|0, | ||
limit: 100, | ||
last_modified: 1 | ||
}, | ||
types: [STATUS_FETCH, STATUS_FETCH_SUCCESS, STATUS_FETCH_FAIL], | ||
}); |
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 | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,59 @@ | ||
import React, {Component} from 'react'; | ||
import {connect} from 'react-redux'; | ||
import {bindActionCreators} from 'redux'; | ||
|
||
import {routerActions} from 'react-router-redux'; | ||
import {fetchStatus} from '../actions/status'; | ||
|
||
import fetchData from '../decorators/fetchData'; | ||
|
||
import AuthForm from './AuthForm'; | ||
import Layout from './Layout'; | ||
import Headline from './Headline'; | ||
import Scrollable from './Scrollable'; | ||
import PortalMenu from './PortalMenu'; | ||
import Folders from './Folders'; | ||
import Letters from './Letters'; | ||
|
||
@connect(state => state) | ||
@connect( | ||
({auth, folders, threads}, {params}) => ({ | ||
auth, | ||
folders, | ||
threads: threads.current[params.folder|0] || [] | ||
}), | ||
(dispatch) => ({ | ||
actions: bindActionCreators({fetchStatus}, dispatch), | ||
routerActions: bindActionCreators({...routerActions}, dispatch), | ||
}) | ||
) | ||
@fetchData( | ||
({auth: email}, {folder}) => ({email, folder}), | ||
({email, folder}, actions) => email && actions.fetchStatus(folder) | ||
) | ||
export default class App extends Component { | ||
handleGlobalClick(evt) { | ||
// todo | ||
} | ||
|
||
render() { | ||
const {auth} = this.props; | ||
return !auth.state ? <AuthForm/> : <h1>Привет, {auth.email}!</h1>; | ||
const {auth, folders, threads, params} = this.props; | ||
const folderId = params.folder|0; | ||
|
||
if (auth.state) { | ||
const sidebar = <Folders models={folders} active={folderId}/>; | ||
const main = <Letters models={threads}/>; | ||
|
||
return <div onClick={(evt) => this.handleGlobalClick(evt)}> | ||
<Headline/> | ||
<PortalMenu /> | ||
<Layout | ||
bordered | ||
left={<Scrollable content={sidebar}/>} | ||
main={<Scrollable content={main}/>} | ||
/> | ||
</div>; | ||
} else { | ||
return <AuthForm/>; | ||
} | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import classNames from 'classnames'; | ||
import React, {Component, PropTypes} from 'react'; | ||
|
||
export default class Avatar extends Component { | ||
render() { | ||
const {src, size} = this.props; | ||
const classes = classNames({ | ||
'avatar': true, | ||
'avatar_rounded': true, | ||
[`avatar_size_${size}`]: size | ||
}); | ||
|
||
//return <div className={classes}/>; | ||
return <img src={(src + '').replace(/&/g, '&')} draggable="false" className={classes}/>; | ||
} | ||
}; |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React, {Component, PropTypes} from 'react'; | ||
|
||
import FoldersItem from './FoldersItem'; | ||
|
||
export default class Folders extends Component { | ||
render() { | ||
const {models, active} = this.props; | ||
|
||
return ( | ||
<div className="nav nav_expanded"> | ||
{models.map(folder => <FoldersItem | ||
key={folder.id} | ||
model={folder} | ||
active={folder.id == active}/> | ||
)} | ||
</div> | ||
); | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React, {Component} from 'react'; | ||
import classNames from 'classnames'; | ||
|
||
import Icon from './Icon'; | ||
|
||
export default class FoldersItem extends Component { | ||
render() { | ||
const {model, active} = this.props; | ||
const classes = classNames({ | ||
'nav__item': true, | ||
'nav__item_active': active, | ||
'nav__item_shortcut': model.system, | ||
'nav__item_highlight': false | ||
}); | ||
|
||
return ( | ||
<a key={model.id} href={`/${model.id}/`} className={classes}> | ||
<span className="nav__ico"> | ||
<Icon map="folder" mod={model.type} size="m"/> | ||
</span> | ||
|
||
{model.messages_unread | ||
? <span className="nav__badge">{model.messages_unread}</span> | ||
: null | ||
} | ||
|
||
<span className="nav__txt">{model.name}</span> | ||
</a> | ||
); | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import React from 'react'; | ||
|
||
export default () => (<div className="headline"></div>); |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import classNames from 'classnames'; | ||
import React, {Component} from 'react'; | ||
|
||
export default class Layout extends Component { | ||
render() { | ||
const {left, main, right, bordered} = this.props; | ||
const classes = classNames({ | ||
'layout': true, | ||
'layout_size_m': true, | ||
'layout_type_2pane': true, | ||
'layout_left-size_11': true, | ||
'layout_right-size_12': true, | ||
'layout_sidebar-size_12': true, | ||
'layout_bordered': bordered | ||
}); | ||
|
||
return ( | ||
<div className={classes}> | ||
<div className="layout__column layout__column_left">{left}</div> | ||
<div className="layout__main-frame">{main}</div> | ||
<div className="layout__column layout__column_right">{right}</div> | ||
</div> | ||
); | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import classNames from 'classnames'; | ||
import React, {Component} from 'react'; | ||
|
||
import Icon from './Icon'; | ||
|
||
const statusToIcoMap = { | ||
'unread': 'letterstatus', | ||
'flagged': 'toolbar' | ||
}; | ||
|
||
const statusToIcoMod = { | ||
'unread': 'unread', | ||
'flagged': 'mark' | ||
}; | ||
|
||
export default class LetterStatus extends Component { | ||
render() { | ||
const {name, state, size} = this.props; | ||
const classes = classNames({ | ||
'letter-status': true, | ||
[`letter-status_${name}`]: true, | ||
[`letter-status_${name}_${state}`]: true, | ||
}); | ||
|
||
return <div className={classes}> | ||
<Icon | ||
map={statusToIcoMap[name]} | ||
mod={statusToIcoMod[name]} | ||
size={size} | ||
/> | ||
</div>; | ||
} | ||
}; |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import classNames from 'classnames'; | ||
import React, {Component} from 'react'; | ||
|
||
import LettersItem from './LettersItem'; | ||
|
||
export default class Letters extends Component { | ||
handleToggleSelect(evt, model) { | ||
// todo | ||
evt.preventDefault(); | ||
} | ||
|
||
render() { | ||
const {models, selection} = this.props; | ||
|
||
const classes = classNames({ | ||
'dataset': true, | ||
'dataset_fluid': true, | ||
'dataset_select-mode_off': true | ||
}); | ||
|
||
const fragment = ( | ||
<div className="dataset-letters"> | ||
<div className={classes}> | ||
<div className="dataset__items">{models.map((model) => { | ||
return <LettersItem | ||
key={model.id} | ||
model={model} | ||
selected={false} | ||
onToggleSelect={(evt) => this.handleToggleSelect(evt, model)} | ||
/> | ||
})}</div> | ||
</div> | ||
</div> | ||
); | ||
|
||
return fragment; | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import classNames from 'classnames'; | ||
import React, {Component} from 'react'; | ||
|
||
import Avatar from './Avatar'; | ||
import Button from './Button'; | ||
import Swipeable from './Swipeable'; | ||
import LetterStatus from './LetterStatus'; | ||
|
||
const DAY = 60 * 60 * 24 * 1000; | ||
const Months = 'Янв Фев Мар Апр Мая Июн Июл Авг Сен Окт Ноя Дек'.split(' '); | ||
|
||
function pad(number) { | ||
return (number < 10) ? '0' + number : number; | ||
} | ||
|
||
function letterTime(time) { | ||
time *= 1000; | ||
|
||
const now = Date.now(); | ||
const date = new Date(time); | ||
|
||
if (now - time > DAY) { | ||
return date.getDate() + ' ' + Months[date.getMonth()]; | ||
} else { | ||
return date.getHours() + ':' + pad(date.getMinutes()); | ||
} | ||
} | ||
|
||
export default class LettersItem extends Component { | ||
render() { | ||
const {model, selected, onToggleSelect} = this.props; | ||
const classes = classNames({ | ||
'dataset__item': true, | ||
'dataset__item_unread': model.flags.unread, | ||
'dataset__item_active': false, | ||
'dataset__item_selected': selected, | ||
}); | ||
|
||
const actions = ( | ||
<div className="dataset__swipe-actions"> | ||
<Button ico="toolbar_unread" short borderless /> | ||
<Button ico="toolbar_mark" short borderless /> | ||
<Button ico="toolbar_remove" short borderless/> | ||
<Button ico="toolbar_spam" short borderless/> | ||
<Button ico="toolbar_more" short borderless/> | ||
</div> | ||
); | ||
|
||
const itemRow = ( | ||
<div className="dataset__item-row"> | ||
<div className="dataset__info"> | ||
<div className="dataset__addrs"> | ||
{ | ||
model.correspondents.from[0].name || | ||
model.correspondents.from[0].email || | ||
'Неизвестно' | ||
} | ||
</div> | ||
|
||
<div className="dataset__subj"> | ||
<div className="dataset__status"> | ||
<LetterStatus | ||
name="flagged" | ||
state={model.flags.flagged} | ||
/> | ||
</div> | ||
|
||
{model.length > 1 ? <div className="dataset__badge">{model.length}</div> : null} | ||
{model.subject} | ||
|
||
<div className="dataset__snippet">{model.snippet}</div> | ||
</div> | ||
</div> | ||
|
||
<div className="dataset__attach" dangerouslySetInnerHTML={model.flags.attach ? {__html: '📎'} : null}/> | ||
<div className="dataset__date">{letterTime(model.date)}</div> | ||
</div> | ||
); | ||
|
||
return ( | ||
<a | ||
className={classes} | ||
title={model.subject} | ||
href={`/${model.folder}/${model.id}/`} | ||
> | ||
<div className="dataset__avatar-cover"> | ||
<div className="dataset__status"> | ||
<LetterStatus | ||
name="unread" | ||
state={model.flags.unread} | ||
/> | ||
</div> | ||
|
||
<div className="dataset__avatar" onClick={onToggleSelect}> | ||
<Avatar | ||
size="s" | ||
src={model.correspondents.from[0].avatars.default} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<Swipeable | ||
underlay={actions} | ||
content={itemRow} | ||
/> | ||
</a> | ||
); | ||
} | ||
} |
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 | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React, {Component} from 'react'; | ||
|
||
import Button from './Button'; | ||
import Layout from './Layout'; | ||
|
||
export default class ProtalMenu extends Component { | ||
render() { | ||
const {selectedCount, selectionActions, threads} = this.props; | ||
const logo = <span className="portal-menu__logo" alt="Почта@Mail.Ru" title="Почта@Mail.Ru"/>; | ||
const actions = (<div> | ||
<Button | ||
onTap={(evt) => selectionActions.selectAll(threads)} | ||
text="Выделить все" | ||
ico="toolbar_select-all" | ||
borderless | ||
short | ||
size="xl"/> | ||
|
||
{selectedCount ? <span class="portal-menu__title">{selectedCount}</span> : null} | ||
</div>); | ||
|
||
return ( | ||
<div className="portal-menu"> | ||
<Layout | ||
left={logo} | ||
main={actions} | ||
/> | ||
</div> | ||
); | ||
} | ||
}; |
Oops, something went wrong.