Skip to content

Commit 0b3697b

Browse files
committed
upload
1 parent 205a099 commit 0b3697b

10 files changed

Lines changed: 391 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const FILES_REQUEST = 'FILES_REQUEST';
2+
export const FILES_RECEIVE = 'FILES_RECEIVE';
3+
4+
export const FILES_UPLOAD_START = 'FILES_UPLOAD_START';
5+
export const FILES_UPLOAD_END = 'FILES_UPLOAD_END';
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import * as t from './actionTypes';
2+
import api from 'lib/api';
3+
import messages from 'lib/text';
4+
5+
function receiveFiles(files) {
6+
return {
7+
type: t.FILES_RECEIVE,
8+
files
9+
};
10+
}
11+
12+
function filesUploadStart() {
13+
return {
14+
type: t.FILES_UPLOAD_START
15+
};
16+
}
17+
18+
function filesUploadEnd() {
19+
return {
20+
type: t.FILES_UPLOAD_END
21+
};
22+
}
23+
24+
export function fetchFiles() {
25+
return (dispatch, getState) => {
26+
return api.files
27+
.list()
28+
.then(({ status, json }) => {
29+
dispatch(receiveFiles(json));
30+
})
31+
.catch(error => {});
32+
};
33+
}
34+
35+
export function uploadFiles(form) {
36+
return (dispatch, getState) => {
37+
dispatch(filesUploadStart());
38+
return api.files
39+
.upload(form)
40+
.then(() => {
41+
dispatch(filesUploadEnd());
42+
dispatch(fetchFiles());
43+
})
44+
.catch(error => {
45+
dispatch(filesUploadEnd());
46+
});
47+
};
48+
}
49+
50+
export function deleteFile(fileName) {
51+
return (dispatch, getState) => {
52+
return api.files
53+
.delete(fileName)
54+
.then(() => {
55+
dispatch(fetchFiles());
56+
})
57+
.catch(error => {});
58+
};
59+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import Dropzone from 'react-dropzone';
3+
import messages from 'lib/text';
4+
import style from './style.css';
5+
6+
import Snackbar from 'material-ui/Snackbar';
7+
import FlatButton from 'material-ui/FlatButton';
8+
9+
export default class MultiUploader extends React.Component {
10+
onDrop = files => {
11+
let form = new FormData();
12+
files.map(file => {
13+
form.append('file', file);
14+
});
15+
this.props.onUpload(form);
16+
};
17+
18+
render() {
19+
const { uploading } = this.props;
20+
return (
21+
<div>
22+
<Dropzone
23+
onDrop={this.onDrop}
24+
multiple={true}
25+
disableClick={true}
26+
ref={node => {
27+
this.dropzone = node;
28+
}}
29+
style={{}}
30+
className={style.dropzone + (uploading ? ' ' + style.uploading : '')}
31+
activeClassName={style.dropzoneActive}
32+
rejectClassName={style.dropzoneReject}
33+
>
34+
<div className={style.dropzoneEmpty}>
35+
{messages.help_dropHere}
36+
<FlatButton
37+
label={messages.chooseImage}
38+
className={style.button}
39+
onClick={() => {
40+
this.dropzone.open();
41+
}}
42+
/>
43+
</div>
44+
</Dropzone>
45+
46+
<Snackbar open={uploading} message={messages.messages_uploading} />
47+
</div>
48+
);
49+
}
50+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
.dropzone {
2+
margin: 20px;
3+
opacity: 1;
4+
transition: opacity .2s ease-in-out;
5+
}
6+
.uploading {
7+
opacity: 0;
8+
}
9+
.dropzoneEmpty {
10+
color: #a1a1a1;
11+
font-size: 16px;
12+
border: 2px dashed rgba(0,0,0,0.1);
13+
padding: 80px 0;
14+
text-align: center;
15+
}
16+
.dropzoneActive {
17+
background-color: rgba(18,179,117, 0.4);
18+
}
19+
.dropzoneReject {
20+
background-color: rgba(244,67,54,0.8);
21+
}
22+
.dropzoneReject .list,
23+
.dropzoneActive .list {
24+
opacity: 0.3
25+
}
26+
.dropzoneActive .button {
27+
opacity: 0;
28+
}
29+
.button {
30+
margin-left: 10px !important;
31+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import React from 'react';
2+
3+
import moment from 'moment';
4+
import messages from 'lib/text';
5+
import * as helper from 'lib/helper';
6+
import DeleteConfirmation from 'modules/shared/deleteConfirmation';
7+
import style from './style.css';
8+
import FileUploader from './fileUploader';
9+
10+
import Paper from 'material-ui/Paper';
11+
import FontIcon from 'material-ui/FontIcon';
12+
import IconButton from 'material-ui/IconButton';
13+
import IconMenu from 'material-ui/IconMenu';
14+
import MenuItem from 'material-ui/MenuItem';
15+
const Fragment = React.Fragment;
16+
17+
const iconButtonElement = (
18+
<IconButton touch={true}>
19+
<FontIcon color="rgb(189, 189, 189)" className="material-icons">
20+
more_vert
21+
</FontIcon>
22+
</IconButton>
23+
);
24+
25+
class FileItem extends React.Component {
26+
constructor(props) {
27+
super(props);
28+
this.state = {
29+
openDelete: false
30+
};
31+
}
32+
33+
showDelete = () => {
34+
this.setState({ openDelete: true });
35+
};
36+
37+
hideDelete = () => {
38+
this.setState({ openDelete: false });
39+
};
40+
41+
handleDelete = () => {
42+
const fileName = this.props.file.file;
43+
this.props.onDelete(fileName);
44+
this.hideDelete();
45+
};
46+
47+
render() {
48+
const { file, settings } = this.props;
49+
const fileName = file.file;
50+
const fileUrl = `${settings.domain}/${file.file}`;
51+
const modifiedDate = moment(file.modified);
52+
const modifiedDateFormated = modifiedDate.format(`${settings.date_format}`);
53+
const fileSizeFormated = helper.formatFileSize(file.size);
54+
55+
return (
56+
<div className={style.item + ' row row--no-gutter middle-xs'}>
57+
<div className={style.name + ' col-xs-5'}>
58+
<a href={fileUrl} target="_blank" rel="noopener">
59+
{file.file}
60+
</a>
61+
</div>
62+
<div className={style.date + ' col-xs-3'}>{modifiedDateFormated}</div>
63+
<div className={style.size + ' col-xs-2'}>{fileSizeFormated}</div>
64+
<div className={style.more + ' col-xs-2'}>
65+
<IconMenu iconButtonElement={iconButtonElement}>
66+
<MenuItem onClick={this.showDelete}>
67+
{messages.actions_delete}
68+
</MenuItem>
69+
</IconMenu>
70+
<DeleteConfirmation
71+
open={this.state.openDelete}
72+
isSingle={true}
73+
itemsCount={1}
74+
itemName={fileName}
75+
onCancel={this.hideDelete}
76+
onDelete={this.handleDelete}
77+
/>
78+
</div>
79+
</div>
80+
);
81+
}
82+
}
83+
84+
export default class FileList extends React.Component {
85+
constructor(props) {
86+
super(props);
87+
}
88+
89+
componentDidMount() {
90+
this.props.onLoad();
91+
}
92+
93+
render() {
94+
const { files, settings, onDelete, onUpload, uploading } = this.props;
95+
let listItems = files.map((file, index) => (
96+
<FileItem
97+
key={index}
98+
file={file}
99+
settings={settings}
100+
onDelete={onDelete}
101+
/>
102+
));
103+
104+
return (
105+
<Fragment>
106+
<div className={style.head + ' row row--no-gutter'}>
107+
<div className="col-xs-5">{messages.fileName}</div>
108+
<div className="col-xs-3">{messages.fileModified}</div>
109+
<div className="col-xs-2">{messages.fileSize}</div>
110+
<div className="col-xs-2" />
111+
</div>
112+
<Paper className="paper-box" zDepth={1}>
113+
{listItems}
114+
</Paper>
115+
<FileUploader onUpload={onUpload} uploading={uploading} />
116+
</Fragment>
117+
);
118+
}
119+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
import { Link } from 'react-router-dom';
3+
import messages from 'lib/text';
4+
import FontIcon from 'material-ui/FontIcon';
5+
import IconButton from 'material-ui/IconButton';
6+
7+
const Buttons = () => null;
8+
9+
export default Buttons;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.item {
2+
font-size: 14px;
3+
padding: 4px 10px;
4+
border-bottom: 1px solid rgb(224, 224, 224);
5+
}
6+
7+
.item:last-of-type {
8+
border-bottom: none;
9+
}
10+
11+
.item:hover{
12+
background-color: rgba(0, 0, 0, 0.05);
13+
}
14+
15+
.name a {
16+
color: rgb(0,142,180);
17+
text-decoration: none;
18+
overflow: hidden;
19+
text-overflow: ellipsis;
20+
white-space: nowrap;
21+
display: block;
22+
}
23+
24+
.name a:hover {
25+
text-decoration: underline;
26+
}
27+
28+
.date, .size {
29+
color: rgba(0, 0, 0, 0.54);
30+
text-align: right;
31+
}
32+
33+
.more {
34+
text-align: right;
35+
}
36+
37+
.head {
38+
color: rgba(0, 0, 0, 0.54);
39+
font-size: 14px;
40+
font-weight: 500;
41+
padding: 16px 16px 0 26px;
42+
text-align: right;
43+
}
44+
45+
.head div:first-of-type {
46+
text-align: left;
47+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { connect } from 'react-redux';
2+
import { withRouter } from 'react-router';
3+
import Buttons from './components/headButtons';
4+
5+
const mapStateToProps = (state, ownProps) => {
6+
return {};
7+
};
8+
9+
const mapDispatchToProps = (dispatch, ownProps) => {
10+
return {};
11+
};
12+
13+
export default withRouter(
14+
connect(
15+
mapStateToProps,
16+
mapDispatchToProps
17+
)(Buttons)
18+
);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { connect } from 'react-redux';
2+
import { fetchFiles, uploadFiles, deleteFile } from '../actions';
3+
import Form from './components/form';
4+
5+
const mapStateToProps = state => {
6+
return {
7+
files: state.files.files,
8+
uploading: state.files.uploading,
9+
settings: state.settings.settings
10+
};
11+
};
12+
13+
const mapDispatchToProps = dispatch => {
14+
return {
15+
onLoad: () => {
16+
dispatch(fetchFiles());
17+
},
18+
onDelete: fileName => {
19+
dispatch(deleteFile(fileName));
20+
},
21+
onUpload: form => {
22+
dispatch(uploadFiles(form));
23+
}
24+
};
25+
};
26+
27+
export default connect(
28+
mapStateToProps,
29+
mapDispatchToProps
30+
)(Form);

0 commit comments

Comments
 (0)