Skip to content

Instantly share code, notes, and snippets.

@sasafister
Created December 21, 2017 19:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sasafister/ccc6c3f01352925bd0d46d1b8ee15375 to your computer and use it in GitHub Desktop.
Save sasafister/ccc6c3f01352925bd0d46d1b8ee15375 to your computer and use it in GitHub Desktop.
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
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