Skip to content

Commit 56d04f6

Browse files
committed
finish pages
1 parent 88c0c05 commit 56d04f6

12 files changed

Lines changed: 540 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 PAGES_REQUEST = 'PAGES_REQUEST';
2+
export const PAGES_RECEIVE = 'PAGES_RECEIVE';
3+
4+
export const PAGE_REQUEST = 'PAGE_REQUEST';
5+
export const PAGE_RECEIVE = 'PAGE_RECEIVE';

src/admin/client/pages/actions.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as t from './actionTypes';
2+
import api from 'lib/api';
3+
import messages from 'lib/text';
4+
5+
function receivePages(pages) {
6+
return {
7+
type: t.PAGES_RECEIVE,
8+
pages
9+
};
10+
}
11+
12+
export function receivePage(pageEdit) {
13+
return {
14+
type: t.PAGE_RECEIVE,
15+
pageEdit
16+
};
17+
}
18+
19+
export function fetchPages() {
20+
return (dispatch, getState) => {
21+
return api.pages
22+
.list()
23+
.then(({ status, json }) => {
24+
dispatch(receivePages(json));
25+
})
26+
.catch(error => {});
27+
};
28+
}
29+
30+
export function fetchPage(id) {
31+
return (dispatch, getState) => {
32+
return api.pages
33+
.retrieve(id)
34+
.then(({ status, json }) => {
35+
dispatch(receivePage(json));
36+
})
37+
.catch(error => {});
38+
};
39+
}
40+
41+
export function createPage(page) {
42+
return (dispatch, getState) => {
43+
return api.pages
44+
.create(page)
45+
.then(({ status, json }) => {
46+
dispatch(fetchPages());
47+
})
48+
.catch(error => {});
49+
};
50+
}
51+
52+
export function updatePage(page) {
53+
return (dispatch, getState) => {
54+
return api.pages
55+
.update(page.id, page)
56+
.then(({ status, json }) => {
57+
dispatch(receivePage(json));
58+
})
59+
.catch(error => {});
60+
};
61+
}
62+
63+
export function deletePage(pageId) {
64+
return (dispatch, getState) => {
65+
return api.pages
66+
.delete(pageId)
67+
.then(({ status, json }) => {
68+
dispatch(fetchPages());
69+
})
70+
.catch(error => {});
71+
};
72+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import React from 'react';
2+
import { Field, reduxForm } from 'redux-form';
3+
import { TextField } from 'redux-form-material-ui';
4+
5+
import { CustomToggle } from 'modules/shared/form';
6+
import Editor from 'modules/shared/editor';
7+
import TagsInput from 'react-tagsinput';
8+
import messages from 'lib/text';
9+
import style from './style.css';
10+
import api from 'lib/api';
11+
12+
import Paper from 'material-ui/Paper';
13+
import Divider from 'material-ui/Divider';
14+
import RaisedButton from 'material-ui/RaisedButton';
15+
16+
const TagsField = ({ input, placeholder }) => {
17+
const tagsArray =
18+
input.value && Array.isArray(input.value) ? input.value : [];
19+
return (
20+
<TagsInput
21+
value={tagsArray}
22+
inputProps={{ placeholder: placeholder }}
23+
onChange={tags => {
24+
input.onChange(tags);
25+
}}
26+
/>
27+
);
28+
};
29+
30+
const validate = values => {
31+
const errors = {};
32+
const requiredFields = ['slug', 'meta_title'];
33+
34+
requiredFields.map(field => {
35+
if (!values.is_system && values && !values[field]) {
36+
errors[field] = messages.errors_required;
37+
}
38+
});
39+
40+
return errors;
41+
};
42+
43+
const asyncValidate = (values /*, dispatch */) => {
44+
return new Promise((resolve, reject) => {
45+
if (!values.slug && values.is_system) {
46+
resolve();
47+
} else {
48+
api.sitemap.retrieve({ path: values.slug }).then(({ status, json }) => {
49+
if (status === 404) {
50+
resolve();
51+
} else {
52+
if (json && !Object.is(json.resource, values.id)) {
53+
reject({ slug: messages.errors_urlTaken });
54+
} else {
55+
resolve();
56+
}
57+
}
58+
});
59+
}
60+
});
61+
};
62+
63+
class EditPageForm extends React.Component {
64+
constructor(props) {
65+
super(props);
66+
}
67+
68+
componentDidMount() {
69+
this.props.onLoad();
70+
}
71+
72+
componentWillUnmount() {
73+
this.props.eraseData();
74+
}
75+
76+
render() {
77+
let {
78+
handleSubmit,
79+
pristine,
80+
submitting,
81+
initialValues,
82+
pageId
83+
} = this.props;
84+
const isAdd = pageId === null || pageId === undefined;
85+
86+
if (initialValues) {
87+
return (
88+
<form onSubmit={handleSubmit}>
89+
<Paper className="paper-box" zDepth={1}>
90+
<div className={style.innerBox}>
91+
<Field
92+
name="meta_title"
93+
component={TextField}
94+
floatingLabelText={messages.pageTitle}
95+
fullWidth={true}
96+
/>
97+
<br />
98+
<Field
99+
name="slug"
100+
component={TextField}
101+
floatingLabelText={messages.slug}
102+
fullWidth={true}
103+
disabled={initialValues.is_system}
104+
/>
105+
<p className="field-hint">{messages.help_slug}</p>
106+
<Field
107+
name="meta_description"
108+
component={TextField}
109+
floatingLabelText={messages.metaDescription}
110+
fullWidth={true}
111+
/>
112+
<div className="field-hint" style={{ marginTop: 40 }}>
113+
{messages.content}
114+
</div>
115+
<div style={{ marginBottom: 50 }}>
116+
<Field name="content" component={Editor} />
117+
</div>
118+
{messages.tags}
119+
<Field
120+
name="tags"
121+
component={TagsField}
122+
placeholder={messages.newTag}
123+
/>
124+
<div style={{ maxWidth: 256 }}>
125+
<Field
126+
component={CustomToggle}
127+
name="enabled"
128+
label={messages.enabled}
129+
style={{ paddingTop: 16, paddingBottom: 16 }}
130+
disabled={initialValues.is_system}
131+
/>
132+
</div>
133+
</div>
134+
<div
135+
className={
136+
'buttons-box ' +
137+
(pristine && !isAdd
138+
? 'buttons-box-pristine'
139+
: 'buttons-box-show')
140+
}
141+
>
142+
<RaisedButton
143+
type="submit"
144+
label={isAdd ? messages.add : messages.save}
145+
primary={true}
146+
className={style.button}
147+
disabled={pristine || submitting}
148+
/>
149+
</div>
150+
</Paper>
151+
</form>
152+
);
153+
} else {
154+
return null;
155+
}
156+
}
157+
}
158+
159+
export default reduxForm({
160+
form: 'EditPageForm',
161+
validate,
162+
asyncValidate,
163+
asyncBlurFields: ['slug'],
164+
enableReinitialize: true
165+
})(EditPageForm);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
import { Link } from 'react-router-dom';
3+
import messages from 'lib/text';
4+
import DeleteConfirmation from 'modules/shared/deleteConfirmation';
5+
import FontIcon from 'material-ui/FontIcon';
6+
import IconButton from 'material-ui/IconButton';
7+
import FlatButton from 'material-ui/FlatButton';
8+
const Fragment = React.Fragment;
9+
10+
export default class Buttons extends React.Component {
11+
constructor(props) {
12+
super(props);
13+
this.state = {
14+
openDelete: false
15+
};
16+
}
17+
18+
openDelete = () => {
19+
this.setState({ openDelete: true });
20+
};
21+
22+
closeDelete = () => {
23+
this.setState({ openDelete: false });
24+
};
25+
26+
deletePage = () => {
27+
this.setState({ openDelete: false });
28+
this.props.onDelete(this.props.page.id);
29+
};
30+
31+
render() {
32+
const { page } = this.props;
33+
const pageName =
34+
page && page.meta_title && page.meta_title.length > 0
35+
? page.meta_title
36+
: 'Draft';
37+
38+
if (page && !page.is_system) {
39+
return (
40+
<Fragment>
41+
<IconButton
42+
touch={true}
43+
tooltipPosition="bottom-left"
44+
tooltip={messages.actions_delete}
45+
onClick={this.openDelete}
46+
>
47+
<FontIcon color="#fff" className="material-icons">
48+
delete
49+
</FontIcon>
50+
</IconButton>
51+
{page.enabled && (
52+
<a href={page.url} target="_blank">
53+
<IconButton
54+
touch={true}
55+
tooltipPosition="bottom-left"
56+
tooltip={messages.viewOnWebsite}
57+
>
58+
<FontIcon color="#fff" className="material-icons">
59+
open_in_new
60+
</FontIcon>
61+
</IconButton>
62+
</a>
63+
)}
64+
<DeleteConfirmation
65+
open={this.state.openDelete}
66+
isSingle={true}
67+
itemsCount={1}
68+
itemName={pageName}
69+
onCancel={this.closeDelete}
70+
onDelete={this.deletePage}
71+
/>
72+
</Fragment>
73+
);
74+
} else {
75+
return null;
76+
}
77+
}
78+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.button {
2+
margin-left: 12px;
3+
}
4+
5+
.innerBox {
6+
padding: 30px;
7+
}
8+
9+
.error {
10+
color: rgb(244, 67, 54);
11+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { connect } from 'react-redux';
2+
import { withRouter } from 'react-router';
3+
import { deletePage } from '../actions';
4+
import Buttons from './components/headButtons';
5+
6+
const mapStateToProps = (state, ownProps) => {
7+
return {
8+
page: state.pages.pageEdit
9+
};
10+
};
11+
12+
const mapDispatchToProps = (dispatch, ownProps) => {
13+
return {
14+
onDelete: id => {
15+
dispatch(deletePage(id));
16+
ownProps.history.push('/admin/pages');
17+
}
18+
};
19+
};
20+
21+
export default withRouter(
22+
connect(
23+
mapStateToProps,
24+
mapDispatchToProps
25+
)(Buttons)
26+
);

0 commit comments

Comments
 (0)