Skip to content

Commit caea84a

Browse files
committed
Add main page, generic input, localeProvider
1 parent 9837955 commit caea84a

File tree

5 files changed

+238
-24
lines changed

5 files changed

+238
-24
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"antd": "2.13.6",
1414
"babel-polyfill": "^6.26.0",
15+
"moment": "^2.19.1",
1516
"prop-types": "^15.6.0",
1617
"react": "15.6.2",
1718
"react-dom": "15.6.2",

src/components/App.js

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,40 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import Container from './common/Container';
4+
import { Route, NavLink } from 'react-router-dom';
5+
import { Layout, Menu, Breadcrumb, Icon, LocaleProvider } from 'antd';
6+
import enUS from 'antd/lib/locale-provider/en_US';
47

5-
import { Layout, Menu, Breadcrumb, Icon } from 'antd';
8+
import CatalogListPage from "./catalog/CatalogListPage";
69
const { Header, Content, Footer } = Layout;
710

811
class App extends Component {
912
render() {
1013
return (
11-
<Layout className="layout">
12-
<Header style={{background: "#fff"}}>
14+
<LocaleProvider locale={enUS}>
15+
<Layout className="layout">
16+
<Header style={{background: "#fff"}}>
17+
<Container>
18+
<span>User: <b>Tester</b></span>
19+
<Menu
20+
mode="horizontal"
21+
selectable={false}
22+
style={{ lineHeight: '63px', display: 'inline'}}
23+
>
24+
<Menu.Item style={{float: "right"}}>Log out <Icon type="logout"/></Menu.Item>
25+
</Menu>
26+
</Container>
27+
</Header>
1328
<Container>
14-
<span>Пользователь: <b>Tester</b></span>
15-
<Menu
16-
mode="horizontal"
17-
selectable={false}
18-
style={{ lineHeight: '63px', display: 'inline'}}
19-
>
20-
<Menu.Item style={{float: "right"}}>Выйти <Icon type="logout"/></Menu.Item>
21-
</Menu>
29+
<Content style={{ minHeight: "calc(100vh - 130px)", padding: "20px" }}>
30+
<Route path={"/"} component={CatalogListPage}/>
31+
</Content>
32+
<Footer style={{ textAlign: 'center' }}>
33+
Sergey Sarkisyan ©2017 Built with React and Ant Design
34+
</Footer>
2235
</Container>
23-
</Header>
24-
<Container>
25-
<Content style={{ minHeight: "calc(100vh - 130px)" }}>
26-
{this.props.children}
27-
</Content>
28-
<Footer style={{ textAlign: 'center' }}>
29-
Sergey Sarkisyan ©2017 Built with React and Ant Design
30-
</Footer>
31-
</Container>
32-
</Layout>
36+
</Layout>
37+
</LocaleProvider>
3338
);
3439
}
3540
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from 'react';
2+
import { Breadcrumb, Table } from 'antd';
3+
4+
class CatalogListPage extends React.Component {
5+
6+
constructor(props, context) {
7+
super(props, context);
8+
9+
this.columns = [
10+
{
11+
title: 'Catalog',
12+
dataIndex: 'name',
13+
key: 'class',
14+
sorter: sortByName,
15+
className: 'clickable-cell',
16+
onCellClick: (record) => {
17+
history.replace(`/catalog/${record.class}`);
18+
}
19+
}
20+
];
21+
}
22+
23+
componentDidMount() {
24+
this.setState({catalog: []});
25+
}
26+
27+
28+
render() {
29+
const { catalogs } = this.props;
30+
31+
return (
32+
<div>
33+
<Breadcrumb style={{ margin: '12px 0' }}>
34+
<Breadcrumb.Item>Catalogs</Breadcrumb.Item>
35+
</Breadcrumb>
36+
37+
<div style={{ background: '#fff', padding: 24, minHeight: 280 }}>
38+
<Table
39+
dataSource={catalogs}
40+
columns={this.columns}
41+
rowKey="class"
42+
bordered
43+
size="middle"
44+
pagination={{showSizeChanger: true}}
45+
/>
46+
</div>
47+
</div>
48+
);
49+
}
50+
}
51+
52+
function sortByName(a, b) {
53+
const nameA = a.name.toUpperCase();
54+
const nameB = b.name.toUpperCase();
55+
56+
if (nameA < nameB) {
57+
return -1;
58+
}
59+
if (nameA > nameB) {
60+
return 1;
61+
}
62+
63+
return 0;
64+
}
65+
66+
export default CatalogListPage;

src/components/common/GenericInput.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Form, InputNumber, Input, DatePicker, Select, Checkbox } from 'antd';
4+
import moment from 'moment';
5+
6+
7+
const GenericInput = ({ category, collection = [], collectionType,
8+
type, name, label, onChange, placeholder,
9+
value, error }) => {
10+
11+
function onChangeDate(name) {
12+
return function(date, dateString) {
13+
onChange(name, dateString);
14+
};
15+
}
16+
17+
function onChangeTimestamp(name) {
18+
return function(date) {
19+
let dateString = '';
20+
if (date) { dateString = date.format(); }
21+
onChange(name, dateString);
22+
};
23+
}
24+
25+
function onChangeString(name) {
26+
return function(event) {
27+
onChange(name, event.target.value);
28+
};
29+
}
30+
31+
function onChangeNumber(name) {
32+
return function(value) {
33+
onChange(name, value);
34+
};
35+
}
36+
37+
function onChangeSelect(name) {
38+
return function(value) {
39+
onChange(name, { _id: value, _class: type });
40+
};
41+
}
42+
43+
function onChangeBoolean(name) {
44+
return function(event) {
45+
onChange(name, event.target.checked);
46+
};
47+
}
48+
49+
function getMomentValue(value, dateFormat) {
50+
if (value) {
51+
return moment(value, dateFormat);
52+
}
53+
54+
return null;
55+
}
56+
57+
function filterSelect(input, option) {
58+
return (option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0);
59+
}
60+
61+
let input = null;
62+
const dateFormat = 'YYYY-MM-DD';
63+
const datetimeFormat = 'YYYY-MM-DD HH:mm:ss';
64+
65+
switch (type) {
66+
case '%Library.String':
67+
input = <Input value={value} onChange={onChangeString(name)} name={name}/>;
68+
break;
69+
case '%Library.Boolean':
70+
input = <Checkbox checked={value} onChange={onChangeBoolean(name)} name={name}>{label}</Checkbox>;
71+
break;
72+
case '%Library.Date':
73+
input = (<DatePicker format={dateFormat} value={getMomentValue(value, dateFormat)}
74+
name={name} onChange={onChangeDate(name)}/>);
75+
break;
76+
case '%Library.TimeStamp':
77+
input = (<DatePicker format={datetimeFormat} value={getMomentValue(value, moment.ISO_8601)}
78+
showTime name={name} onChange={onChangeTimestamp(name)}/>);
79+
break;
80+
case '%Library.Integer':
81+
case '%Library.Numeric':
82+
input = <InputNumber name={name} value={value} onChange={onChangeNumber(name)}/>;
83+
break;
84+
default:
85+
if (category === 'form') {
86+
87+
if (!collectionType) {
88+
let options = collection.map(item => {
89+
return <Select.Option key={item._id} value={item._id}>{item.displayName}</Select.Option>;
90+
});
91+
92+
if (value) {
93+
// extract the id and cast it to string (<Select> accepts only string type for 'value' due PropType)
94+
value = value._id.toString();
95+
}
96+
97+
input = (
98+
<Select showSearch style={{ width: 200 }}
99+
value={value}
100+
name={name}
101+
optionFilterProp="children"
102+
filterOption={filterSelect}
103+
onChange={onChangeSelect(name)}>
104+
{options}
105+
</Select>
106+
);
107+
}
108+
109+
}
110+
break;
111+
}
112+
113+
if (input) {
114+
if (type !== '%Library.Boolean') {
115+
return (
116+
<Form.Item label={label}>
117+
{input}
118+
</Form.Item>
119+
);
120+
} else {
121+
return input;
122+
}
123+
124+
} else {
125+
return <div/>;
126+
}
127+
};
128+
129+
GenericInput.propTypes = {
130+
type: PropTypes.string.isRequired,
131+
category: PropTypes.string.isRequired,
132+
collectionType: PropTypes.string.isRequired,
133+
collection: PropTypes.array,
134+
name: PropTypes.string.isRequired,
135+
label: PropTypes.string.isRequired,
136+
onChange: PropTypes.func.isRequired,
137+
placeholder: PropTypes.string,
138+
value: PropTypes.any,
139+
error: PropTypes.string
140+
};
141+
142+
export default GenericInput;

src/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
3-
import { BrowserRouter } from 'react-router-dom';
3+
import { HashRouter } from 'react-router-dom';
44
import App from './components/App';
55
import './index.csp';
66

77
ReactDOM.render(
8-
<BrowserRouter>
8+
<HashRouter>
99
<App />
10-
</BrowserRouter>,
10+
</HashRouter>,
1111
document.getElementById('app')
1212
);

0 commit comments

Comments
 (0)