meteor-interface
Version:
Simple Content Management System to generate your administration interface for Meteor and React.
244 lines (221 loc) • 8.19 kB
JavaScript
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import slugify from 'slugify';
import { Spring } from 'react-spring'
// Packages
import {
Segment,
Header,
Button,
Form,
} from 'semantic-ui-react';
import styled from 'styled-components';
// Components
import Confirmation from '../../components/Confirmation'
import WidgetFormSelector from '../components/WidgetFormSelector'
import { WidgetSelectorContext } from '../../../utils/contexts/WidgetFormContext'
class ContentEdit extends Component {
state = {
changes: false,
loaded: false,
itemState: {},
confirmation: false,
confirmationObject: {}
}
componentWillReceiveProps = (nextProps) => {
const { item = {} } = nextProps
if(!this.state.loaded && item._id){
const keys = Object.keys(item)
const itemState = {}
keys.map(key => {
itemState[key] = item[key]
})
this.setState({ itemState, loaded: true })
}
}
updateValue = (e, { name, value, checked }) => {
const { itemState = {} } = this.state;
itemState[name] = value || checked
this.setState({ itemState, changes: true })
return value;
}
save = () => {
const { itemState } = this.state;
const { history, collection = {}, item = {}, root } = this.props;
const method = `interface.update.${slugify(collection.label, { lower: true })}`;
this.setState({ confirmation: false, loading: true })
const self = this
Meteor.call(method, { item: itemState }, function(error, result){
self.setState({ loading: false })
if(result){
const itemId = item._id || result
notify.success('Changes saved')
history.push(`${root}/collections/${slugify(collection.label, { lower: true })}/${itemId}`)
} else if (error){
notify.error(error.reason)
}
})
}
delete = () => {
const { history, collection = {}, item = {}, root } = this.props;
this.setState({ confirmation: false, loading: true })
const self = this
const method = `interface.delete.${slugify(collection.label, { lower: true })}`;
Meteor.call(method, { itemId: item._id }, function(error, result){
self.setState({ loading: false })
if(result){
notify.success('Document deleted')
history.push(`${root}/collections/${slugify(collection.label, { lower: true })}`)
} else if (error){
notify.error(error.reason)
}
})
}
toggleConfirmationSave = (e) => {
e.preventDefault();
const confirmationObject = {
title: 'Save and publish the document',
text: 'You are about to save your modification and publish it immediatly',
cancel: () => this.setState({ confirmation: !this.state.confirmation }),
confirm: this.save,
};
this.setState({ confirmation: !this.state.confirmation, confirmationObject });
}
toggleConfirmationDelete = (e) => {
e.preventDefault();
const confirmationObject = {
title: 'Delete the document',
text: 'You are about to delete this document, this cannot be undone.',
cancel: () => this.setState({ confirmation: !this.state.confirmation }),
confirm: this.delete,
};
this.setState({ confirmation: !this.state.confirmation, confirmationObject });
}
render(){
const { itemState = {}, changes, loaded, confirmationObject, confirmation, loading } = this.state;
const { item = {}, history, ready, collection = {}, firstField, config = {}, root } = this.props;
// Extract datas from config
const { collections = [] } = config;
return(
<WidgetSelectorContext.Provider
value={{
collection,
item: itemState,
ready,
updateValue: this.updateValue
}}
>
<ContentEditStyle>
<Spring from={{ opacity: 0, marginLeft: 600 }} to={{ opacity: 1, marginLeft: 0 }}>
{ styles =>
<Segment style={{...styles, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Header content={`Single item from ${collection.label}: ${item._id ? 'EDITION' : 'NEW' }`} as="h5" />
<div>
{item._id ?
<Button
content="DELETE"
size="mini"
icon="trash"
onClick={this.toggleConfirmationDelete}
color="red"
labelPosition="left"
/>
: null }
<Button
content={ changes === false ? "SAVED" : "SAVE"}
size="mini"
icon="save"
onClick={ changes === false ? null : this.toggleConfirmationSave}
color={ changes === false ? "grey" : "green"}
labelPosition="left"
/>
</div>
</Segment> }
</Spring>
<Spring from={{ opacity: 0, marginTop: 600 }} to={{ opacity: 1, marginTop: 0 }}>
{ styles =>
<Segment style={styles} color="green">
<Form loading={loading}>
<WidgetFormSelector
collection={collection}
item={itemState}
ready={ready}
updateValue={this.updateValue}
/>
</Form>
</Segment>
}
</Spring>
<Confirmation
confirmation={confirmation}
loading={loading}
confirmationObject={confirmationObject}
/>
</ContentEditStyle>
</WidgetSelectorContext.Provider>
)
}
}
export default withTracker(({ match, config = {} }) => {
const { collectionSlug, itemId } = match.params
const { collections = [] } = config
let collection = null;
collections.map(coll => {
const slug = slugify(coll.label, { lower: true })
if(slug === collectionSlug)
collection = coll
})
const subscription = Meteor.subscribe(`interface.one.${slugify(collection.label, { lower: true })}`, { itemId })
const ready = subscription.ready()
const firstField = collection.fields[0].name
const item = collection.mongo.findOne({ _id: itemId })
return { collection, ready, item, firstField };
})(ContentEdit);
const ContentEditStyle = styled.div`
h5.header {
letter-spacing:2px;
margin-bottom: 0;
}
.button {
transition: all 0.3s ease-in !important;
}
.image-selector {
.choice {
display: flex;
justify-content: space-between;
flex-direction: column;
.button {
margin-bottom: 3px;
}
}
.wrapper {
display: flex;
align-items: center;
justify-content: space-around;
}
}
.tinymce-selector .wrapper {
padding: 0px !important;
}
.mce-panel.mce-tinymce {
border: none !important;
box-shadow: none;
border-radius: 5px;
overflow: hidden;
}
.mce-top-part::before {
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.incrementation {
color: green;
cursor: pointer;
font-size: 12px;
}
.decrementation {
color: red;
cursor: pointer;
font-size: 12px;
}
`