import React from 'react' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' import Modal from 'react-modal' import isEqual from 'lodash/isEqual' import cloneDeep from 'lodash/cloneDeep' import Admin from './../admin' import Instance from './util/instance' import ModalSelect from './modal-select' import ReusableImages from './reusable-images' import { fetchEntities, createEntity, updateEntity, deleteEntity } from '../actions/index' import { ReusableImagesModalStyles, SelectModalStyles, NotificationModalStyles, MarkdownModalStyles } from './helpers/modal-styles' import { withExitPrompt } from './util/with-exit-prompt' interface PagePartialType { id?: number; fieldsCount?: number; name?: string; visible?: boolean; } interface PagePartialField { id: number; } interface PagePartialProps { contentDownloads: any[]; createEntity: any; deleteEntity: any; deletePagePartial: any; deleteNestedPagePartial: any; errors: string[]; eventSeries: any[]; fetchEntities: any; fields: PagePartialField[]; files: any[]; headerTypes: any[]; images: any[]; instances: any[]; index: number; nested: boolean; nestedPagePartials: any[]; pagePartial: PagePartialType; parentPartialFieldId: number; partials: any[]; passedPagePartial: any; transcripts: any[]; webinars: any[]; updateEntity: any; } interface PagePartialState extends ComponentState { contentDownloads: any[]; copyModalOpen: boolean; eventSeries: any[]; fetching: boolean; fields: PagePartialField[]; files: any[]; headerTypes: any[]; images: any[]; instances: any[]; isExpanded: boolean; markdownModalOpen: boolean; nestedPagePartials: PagePartialType[]; notificationModalOpen: boolean; notificationPageId: number; notificationType: string; pagePartial: PagePartialType; pagePartialSaved: PagePartialType; partialsModalOpen: boolean; reusableImagesModalOpen: boolean; transcripts: any[]; webinars: any[]; } class PagePartial extends React.Component { constructor(props) { super(props); this.state = { contentDownloads: [], copyModalOpen: false, errors: [], eventSeries: [], fetching: false, fields: [], files: [], headerTypes: [], images: [], instances: [], isExpanded: false, markdownModalOpen: false, nestedPagePartials: [], notificationModalOpen: false, notificationPageId: null, notificationType: null, pagePartial: {}, pagePartialSaved: {}, partialsModalOpen: false, reusableImagesModalOpen: false, transcripts: [], webinars: [] } } componentDidMount() { this.setState({ pagePartial: this.props.passedPagePartial }); } checkForChanges() { return !isEqual(this.state.pagePartial, this.state.pagePartialSaved); } changeFieldArgs() { return { thing: "pagePartial", errorsArray: this.state.errors, changesFunction: this.checkForChanges.bind(this) } } mouseDownHandler(e) { $('.handle').addClass('grabbing'); e.target.parentElement.classList.add('dragging-this'); } mouseUpHandler(e) { $('.handle').removeClass('grabbing'); e.target.parentElement.classList.remove('dragging-this'); } clickDelete() { if (this.props.nested) { this.props.deleteNestedPagePartial(this.props.parentPartialFieldId); } else { this.props.deletePagePartial(this.state.pagePartial.id); } } clickCopy() { this.setState({ copyModalOpen: true }); } clickArrow() { const isExpanded = !this.state.isExpanded; const needToFetch = (isExpanded && this.state.fields.length === 0); this.setState({ fetching: needToFetch, isExpanded }, () => { if (needToFetch) { this.props.fetchEntities({ url: `/admin/api/page_partials/${this.state.pagePartial.id}` }).then(() => { this.setState({ fetching: false, fields: this.props.fields, pagePartial: this.props.pagePartial, pagePartialSaved: cloneDeep(this.props.pagePartial), images: this.props.images, files: this.props.files, instances: this.props.instances, nestedPagePartials: this.props.nestedPagePartials, webinars: this.props.webinars, headerTypes: this.props.headerTypes }, () => { Instance.fetchAdditionalNeededData.call(this, { entityName: 'pagePartial', addingEntity: false }); }); }); } else { Admin.setUpNiceSelect({ selector: 'select', func: Admin.changeField.bind(this, this.changeFieldArgs()), adjustWidthSelector: '.instance-fields .nice-select' }); } }); } clickSave() { this.setState({ fetching: true, justSaved: true }, () => { this.props.updateEntity({ id: this.state.pagePartial.id, directory: 'page_partials', entityName: 'pagePartial', entity: this.state.pagePartial }).then(() => { this.setState({ fetching: false, pagePartial: this.props.pagePartial, pagePartialSaved: cloneDeep(this.props.pagePartial), changesToSave: false }); }, () => { this.setState({ fetching: false, errors: this.props.errors }); }); }); } addNestedPagePartial(args) { const { partialId, partialFieldId } = args; const pagePartialFieldId = this.state.pagePartial[`${partialFieldId}_page_partial_field_id`]; this.setState({ fetching: true }); this.props.createEntity({ directory: 'page_partials/create_nested', entityName: 'pagePartial', entity: { page_partial_field_id: pagePartialFieldId, partial_id: partialId, parent_id: this.state.pagePartial.id } }).then(() => { this.setState({ fetching: false, pagePartial: this.props.pagePartial, nestedPagePartials: this.props.nestedPagePartials }); }); } deleteNestedPagePartial(fieldId) { let pagePartialFieldId = this.state.pagePartial[`${fieldId}_page_partial_field_id`]; this.setState({ fetching: true }); this.props.deleteEntity({ directory: 'page_partials/delete_nested', id: 1, data: { parentId: this.state.pagePartial.id, pagePartialFieldId }, callback: (response) => { const { pagePartial, nestedPagePartials } = response; this.setState({ fetching: false, pagePartial, nestedPagePartials }); } }); } selectPage(e) { let pageId = e.target.dataset.id; this.setState({ copyModalOpen: false, notificationModalOpen: true, notificationType: "wait", notificationPageId: pageId }); // TODO: after converting to redux, make this an action: let pagePartial = this.state.pagePartial; $.ajax({ method: 'POST', url: '/admin/api/page_partials/copy', data: { page_partial_id: pagePartial.id, page_id: pageId }, success: (response) => { this.setState({ notificationType: 'success' }); } }); } render() { return(
{ Admin.renderGrayedOut(this.state.fetching) } { Admin.renderSpinner(this.state.fetching) } { this.renderArrowAndButtons() }

{ this.state.pagePartial.name }

{ this.state.isExpanded ? this.renderExpandedPartial() : '' } { this.renderNotification() }

Markdown Syntax

Style Markdown Syntax Example
Bold ** or __ **bold text**
H1 # # Header
H2 ## ## Header
H3 ### ### Header
H4 #### #### Header
H5 ##### ##### Header
H6 ###### ###### Header
Image ![]() ![alt text](images/foo.jpg)
Italic * *italic text*
Horizontal Rule --- or *** or ___ ---
Link []() [visit Teachable](https://teachable.com)
List (Bullet) * or - or + * first item
* second item
Superscript ^ ^superscript
); } renderArrowAndButtons() { return (
{ this.renderHandle() } { this.renderExpandToggle(this.state.pagePartial.fieldsCount, this.state.isExpanded) }
); } renderHandle() { if (this.props.nested) { return null; } else { return( ); } } renderExpandToggle(fieldsCount, isExpanded) { if (fieldsCount > 0) { return ( ); } else { return (
); } } renderExpandedPartial() { return([
{ this.renderFields() }
, { Admin.saveButtonText.call(this) } ,
Close Partial
]); } renderFields() { if (this.state.fields.length > 0) { return Instance.renderFields.call(this, { fields: this.state.fields, entityName: 'pagePartial' }); } else { return
; } } renderNotification() { switch (this.state.notificationType) { case "wait": return(

Copying Partial...

,
); break; case "success": return(

Partial Copied.

Visit Page
); break; default: return null; } } componentDidUpdate() { $('.match-height-layout').matchHeight(); } } const mapStateToProps = (reducers, props) => { return reducers.standardReducer; }; function mapDispatchToProps(dispatch) { return bindActionCreators({ fetchEntities, createEntity, updateEntity, deleteEntity }, dispatch); } export default connect(mapStateToProps, mapDispatchToProps)(withExitPrompt(PagePartial));