Created
December 21, 2017 19:07
-
-
Save sasafister/ccc6c3f01352925bd0d46d1b8ee15375 to your computer and use it in GitHub Desktop.
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
import React, { Component } from 'react' | |
import helpers from '../../utils/helpers' | |
import Categories from '../../utils/categories' | |
import Vendors from '../../utils/vendors' | |
import moment from "moment" | |
import SweetAlert from 'sweetalert-react' | |
import MyEditor from './my_editor' | |
import { convertToRaw, convertFromRaw } from 'draft-js' | |
class AddCustomCourse extends Component { | |
constructor(props) { | |
super(props) | |
if(typeof props.course == 'undefined') { | |
var course = '' | |
} else course = props.course.course | |
this.state = { | |
course : { | |
id: course ? course.id : '', | |
title: course ? course.name : '', | |
description: course ? course.description : '', | |
price_discount: course ? course.price_discount : '', | |
price: course ? course.price : '', | |
image: course ? course.image : '/img/no-image-available.png', | |
link: course ? course.link : '', | |
is_featured: course ? course.is_featured : false, | |
is_custom: course ? course.is_custom : false, | |
is_jumbo: course ? course.is_jumbo : false, | |
published_at: moment().format('YYYY-MM-DD'), | |
vendors: [], | |
category_id: course ? course.category.id : 1, | |
vendor: course ? course.vendor.name : '', | |
long_description: course ? course.long_description : '', | |
isUpdate: false | |
}, | |
alertShow: {state: false, message: ''}, | |
categories: [], | |
} | |
this.onSelectCategory = this.onSelectCategory.bind(this) | |
this.handleInputs = this.handleInputs.bind(this) | |
this.handleSubmit = this.handleSubmit.bind(this) | |
this.onChange = this.onChange.bind(this) | |
} | |
componentDidMount() { | |
helpers.getCategories().then(response => { | |
this.setState({categories: response.data}) | |
}) | |
helpers.getVendors().then(response => { | |
this.setState({vendors: response.data}) | |
}) | |
} | |
onChange(long_description) { | |
this.setState({course: {long_description: JSON.stringify(convertToRaw(long_description))}}) | |
} | |
onSelectCategory(categoryId) { | |
this.setState({category_id: categoryId}) | |
} | |
onSelectVendor(vendor_id) { | |
this.setState({vendor_id}) | |
} | |
handleInputs(event) { | |
const target = event.target; | |
const value = target.type === 'checkbox' ? target.checked : target.value; | |
const name = target.name; | |
this.setState({ | |
[name]: value | |
}) | |
} | |
handleSubmit(e) { | |
e.preventDefault() | |
if(this.state.isUpdate) { | |
helpers.updateCourse(this.state).then(response => { | |
console.log(response) | |
}) | |
} else { | |
console.log(this.state.course) | |
helpers.saveCourse(this.state).then(response => { | |
if(!response.data.success) { | |
this.setState({alertShow: {state: true, message: response.data.message}}) | |
} else { | |
this.setState({ | |
alertShow: {state: true, message: response.data.message} | |
}) | |
} | |
}) | |
} | |
} | |
render() { | |
return( | |
<div className="content-inner"> | |
<SweetAlert | |
show={this.state.alertShow.state} | |
title={this.state.alertShow.message} | |
onConfirm={() => this.setState({alertShow: {state: false, message: '' }})} | |
/> | |
<header className="page-header "> | |
<div className="container-fluid d-flex justify-content-between"> | |
<h2 className="align-middle">Add Custom Course</h2> | |
</div> | |
</header> | |
<div className="card card-padding"> | |
<div className="card-close"> | |
<div className="dropdown"> | |
<button type="button" id="closeCard" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" className="dropdown-toggle"><i className="fa fa-ellipsis-v"></i></button> | |
<div aria-labelledby="closeCard" className="dropdown-menu has-shadow"><a href="#" className="dropdown-item remove"> <i className="fa fa-times"></i>Close</a><a href="#" className="dropdown-item edit"> <i className="fa fa-gear"></i>Edit</a></div> | |
</div> | |
</div> | |
<div className="card-header d-flex align-items-center"> | |
<h3 className="h4">Course details</h3> | |
</div> | |
<div className="card-body"> | |
<form onSubmit={this.handleSubmit}> | |
<div className="form-group"> | |
<input type="text" placeholder="Course title" name="title" value={this.state.course.title} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
<div className="form-group"> | |
<input type="text" placeholder="Course description" name="description" value={this.state.course.description} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
<div className="d-flex col row col"> | |
<div className="form-group mr-2"> | |
<input type="text" placeholder="Course price" name="price" value={this.state.course.price} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
<div className="form-group"> | |
<input type="text" placeholder="Discount price" name="price_discount" value={this.state.course.price_discount} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
</div> | |
<div className="form-group"> | |
<input type="text" placeholder="Link" name="link" value={this.state.course.link} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
<div className="media"> | |
<img className="d-flex col-md-3 mr-3 pl-0 mb-2" src={this.state.course.image} /> | |
<div className="media-body"> | |
<input type="text" placeholder="Course image" name="image" value={this.state.course.image} onChange={this.handleInputs} | |
className="form-control" /> | |
</div> | |
</div> | |
<div className="form-group"> | |
Featured: <input type="checkbox" value={this.state.course.is_featured} checked={this.state.course.is_featured} name="is_featured" className="checkbox-template" onChange={this.handleInputs}/> | |
Custom: <input type="checkbox" value={this.state.is_custom} checked={this.state.course.is_custom} name="is_custom" className="checkbox-template" onChange={this.handleInputs}/> | |
</div> | |
{ this.state.course.is_custom | |
? <MyEditor handleText={this.state.course.long_description} onChange={this.onChange}/> | |
: null | |
} | |
<Categories categories={this.state.categories} onSelectCategory={this.onSelectCategory}/> | |
<div className="form-group"> | |
<input type="text" placeholder="Vendor" name="vendor" value={this.state.course.vendor} className="form-control" onChange={this.handleInputs} /> | |
</div> | |
<div className="form-group"> | |
{ this.props.course | |
? <button type="submit" className="btn btn-primary" onClick={() => this.setState({isUpdate: true})}>Update</button> | |
: <input type="submit" className="btn btn-primary" /> | |
} | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
) | |
} | |
} | |
export default AddCustomCourse |
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
import React, { Component } from 'react' | |
import { Editor, EditorState, RichUtils, convertToRaw, convertFromRaw } from 'draft-js' | |
import {stateToHTML} from 'draft-js-export-html'; | |
import './rich-editor.css' | |
class MyEditor extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { }; | |
if (props.handleText) { | |
this.state.editorState = EditorState.createWithContent(convertFromRaw(JSON.parse(props.handleText))); | |
} else { | |
this.state.editorState = EditorState.createEmpty(); | |
} | |
this.focus = () => this.refs.editor.focus(); | |
this.handleKeyCommand = this._handleKeyCommand.bind(this); | |
this.onTab = this._onTab.bind(this); | |
this.toggleBlockType = this._toggleBlockType.bind(this); | |
this.toggleInlineStyle = this._toggleInlineStyle.bind(this); | |
this.onChange = this.onChange.bind(this) | |
} | |
componentDidMount() { | |
const rawContent = this.props.handleText | |
if (rawContent) { | |
this.setState({ editorState: EditorState.createWithContent(convertFromRaw(rawContent)) }) | |
} else { | |
this.setState({ editorState: EditorState.createEmpty() }); | |
} | |
} | |
onChange(editorState) { | |
const contentState = editorState.getCurrentContent(); | |
// console.log('content state', convertToRaw(contentState)); | |
this.props.onChange(contentState) | |
// this.setState({ | |
// editorState, | |
// }); | |
} | |
_handleKeyCommand(command, editorState) { | |
const newState = RichUtils.handleKeyCommand(editorState, command); | |
if (newState) { | |
this.onChange(newState); | |
return true; | |
} | |
return false; | |
} | |
_onTab(e) { | |
const maxDepth = 4; | |
this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth)); | |
} | |
_toggleBlockType(blockType) { | |
this.onChange( | |
RichUtils.toggleBlockType( | |
this.state.editorState, | |
blockType | |
) | |
); | |
} | |
_toggleInlineStyle(inlineStyle) { | |
this.onChange( | |
RichUtils.toggleInlineStyle( | |
this.state.editorState, | |
inlineStyle | |
) | |
); | |
} | |
render() { | |
const {editorState} = this.state; | |
var contentState = editorState.getCurrentContent(); | |
// If the user changes block type before entering any text, we can | |
// either style the placeholder or hide it. Let's just hide it now. | |
let className = 'RichEditor-editor'; | |
if (!contentState.hasText()) { | |
if (contentState.getBlockMap().first().getType() !== 'unstyled') { | |
className += ' RichEditor-hidePlaceholder'; | |
} | |
} | |
return ( | |
<div className="RichEditor-root"> | |
<BlockStyleControls | |
editorState={editorState} | |
onToggle={this.toggleBlockType} | |
/> | |
<InlineStyleControls | |
editorState={editorState} | |
onToggle={this.toggleInlineStyle} | |
/> | |
<div className={className} onClick={this.focus}> | |
<Editor | |
blockStyleFn={getBlockStyle} | |
customStyleMap={styleMap} | |
editorState={editorState} | |
handleKeyCommand={this.handleKeyCommand} | |
onChange={this.onChange} | |
onTab={this.onTab} | |
placeholder="Tell a story..." | |
ref="editor" | |
spellCheck={true} | |
/> | |
</div> | |
</div> | |
); | |
} | |
} | |
// Custom overrides for "code" style. | |
const styleMap = { | |
CODE: { | |
backgroundColor: 'rgba(0, 0, 0, 0.05)', | |
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace', | |
fontSize: 16, | |
padding: 2, | |
}, | |
}; | |
function getBlockStyle(block) { | |
switch (block.getType()) { | |
case 'blockquote': return 'RichEditor-blockquote'; | |
default: return null; | |
} | |
} | |
class StyleButton extends React.Component { | |
constructor() { | |
super(); | |
this.onToggle = (e) => { | |
e.preventDefault(); | |
this.props.onToggle(this.props.style); | |
}; | |
} | |
render() { | |
let className = 'RichEditor-styleButton'; | |
if (this.props.active) { | |
className += ' RichEditor-activeButton'; | |
} | |
return ( | |
<span className={className} onMouseDown={this.onToggle}> | |
{this.props.label} | |
</span> | |
); | |
} | |
} | |
const BLOCK_TYPES = [ | |
{label: 'H1', style: 'header-one'}, | |
{label: 'H2', style: 'header-two'}, | |
{label: 'H3', style: 'header-three'}, | |
{label: 'H4', style: 'header-four'}, | |
{label: 'H5', style: 'header-five'}, | |
{label: 'H6', style: 'header-six'}, | |
{label: 'Blockquote', style: 'blockquote'}, | |
{label: 'UL', style: 'unordered-list-item'}, | |
{label: 'OL', style: 'ordered-list-item'}, | |
{label: 'Code Block', style: 'code-block'}, | |
]; | |
const BlockStyleControls = (props) => { | |
const {editorState} = props; | |
const selection = editorState.getSelection(); | |
const blockType = editorState | |
.getCurrentContent() | |
.getBlockForKey(selection.getStartKey()) | |
.getType(); | |
return ( | |
<div className="RichEditor-controls"> | |
{BLOCK_TYPES.map((type) => | |
<StyleButton | |
key={type.label} | |
active={type.style === blockType} | |
label={type.label} | |
onToggle={props.onToggle} | |
style={type.style} | |
/> | |
)} | |
</div> | |
); | |
}; | |
var INLINE_STYLES = [ | |
{label: 'Bold', style: 'BOLD'}, | |
{label: 'Italic', style: 'ITALIC'}, | |
{label: 'Underline', style: 'UNDERLINE'}, | |
{label: 'Monospace', style: 'CODE'}, | |
]; | |
const InlineStyleControls = (props) => { | |
var currentStyle = props.editorState.getCurrentInlineStyle(); | |
return ( | |
<div className="RichEditor-controls"> | |
{INLINE_STYLES.map(type => | |
<StyleButton | |
key={type.label} | |
active={currentStyle.has(type.style)} | |
label={type.label} | |
onToggle={props.onToggle} | |
style={type.style} | |
/> | |
)} | |
</div> | |
); | |
}; | |
export default MyEditor |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment