Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4f74c27
Initial Blog Updater refactoring commit
Mar 7, 2018
3ffe8d2
Initial related form commit
Mar 7, 2018
e3b735f
Display real content list in realtime
Mar 7, 2018
da36bfd
Finished blog related items Fields map
Mar 7, 2018
e552f9b
Reimplemented BlogSearchSelect to redux-form Field
Mar 7, 2018
d30a445
Cleaned the code
Mar 7, 2018
bfc5f7c
Implemented blog update
Mar 7, 2018
8c7ef5d
Debugging
Mar 7, 2018
cf6a5b3
Initial Image Upload Field commit
Mar 7, 2018
549a512
Added upload support to File Upload Field
Mar 8, 2018
dd1a039
Implemented files uploads to the bucket #546
Mar 8, 2018
b172483
Cleaned the code. Fixed file upload to a `null` bucket
Mar 8, 2018
050aaaf
Uploaded image validation #546
Mar 8, 2018
fc9f803
Improved error message
Mar 8, 2018
e57816e
UX improvements
Mar 8, 2018
8026b06
Finally fixed related item creation
Mar 8, 2018
760039a
Related Fields remove action
Mar 8, 2018
d989b61
ux improvements
Mar 9, 2018
9959dc7
Finished related item creation flow
Mar 9, 2018
40569c7
Merge branch 'dev' into improve_blog_updated
Mar 26, 2018
3e045b7
Merge branch 'dev' into improve_blog_updated
Mar 27, 2018
8f6835c
Merge branch 'dev' into improve_blog_updated
Mar 29, 2018
cdb0114
Added carousel career image field #638
Mar 29, 2018
22db90e
Prettier updates
Mar 29, 2018
fefa69e
Initial contributors select component
Mar 29, 2018
922db9e
Finished contributors select field logic
Mar 30, 2018
713cffd
Implemented contributor select component #619
Mar 30, 2018
3ccc454
Single page for blog updater
Mar 30, 2018
9396c44
Fixed outdated contributors list api response
Mar 30, 2018
075e5dd
Fixed Blog List design
Mar 30, 2018
9dd5efb
Working on error/success update blog post message
Mar 30, 2018
cd5521e
Implemented error/success message
Mar 30, 2018
68b0658
Merge branch 'dev' into improve_blog_updated
kylepolich Apr 1, 2018
05e182e
Merge branch 'dev' into improve_blog_updated
Apr 6, 2018
7aacd6c
Removed `UNSUPPORTED TYPE` message. It could reduce website performance
Apr 6, 2018
af32290
Improve blogs items rendering speed
Apr 6, 2018
fd30807
Merge remote-tracking branch 'origin/improve_blog_updated' into impro…
Apr 6, 2018
d2ddde3
Removed legacy related routes #652
Apr 6, 2018
ba1d854
Fixed contributors rendering
Apr 6, 2018
1b5259b
Initial add contributor page #631
Apr 6, 2018
9e09904
Styled add contributor form
Apr 6, 2018
43a0450
Simple contributor add form validation
Apr 6, 2018
be47239
Configured basic bio edit field
Apr 6, 2018
a4eb47e
Done with creation logic for client-side
Apr 6, 2018
f14e494
Fixed lambda request call
Apr 6, 2018
6dd0c9e
Removed mock
Apr 6, 2018
97516a6
merge
kylepolich Apr 21, 2018
9af186c
merge
kylepolich Apr 21, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 55 additions & 9 deletions backend/api/v1/contributors.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,63 @@
const express = require('express')
import { orderBy } from 'lodash'

const ContributorsService = require('../../modules/contributors/services/ContributorsService')
const axios = require('axios')
const c = require('../../../config/config.json')

const env = process.env.NODE_ENV === 'dev' ? 'dev' : 'prod'
const base_api = c[env]['base_api'] + env


const filterItems = (items, query) => {
if (!query) {
return items
}

return items.filter(item => {
return (
item.prettyname.toLowerCase().indexOf(query) > -1 ||
item.bio.toLowerCase().indexOf(query) > -1
)
})
}

const addContributor = (data ) => {
return axios.post(base_api + '/blog/contributors/add', data).then(res => res.data)
}

module.exports = cache => {
const router = express.Router()
router.get('/list', function(req, res) {
ContributorsService.getAllContributors()
.then(contributors => {
res.send(contributors)
})
.catch(err => {
res.send(err)
})

router.get('/', (req, res) => {
const { q } = req.query
let contributors = cache().contributors

contributors = filterItems(
orderBy(
Object.keys(contributors).map(id => ({
...contributors[id],
id
})),
'sort_rank'
),
q
)

return res.send(contributors)
})

router.get('/list', (req, res) => {
const contributors = cache().contributors
res.send(contributors)
})

router.post('/', (req, res) => {
const contributor = req.body

addContributor(contributor)
.then(data => res.send(data))
.catch(error => res.send({ success: false, error: error.message }))
})

return router
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"cookie-session": "^2.0.0-beta.3",
"css-loader": "^0.26.2",
"draft-js": "^0.10.5",
"draftjs-md-converter": "^0.1.7",
"draftjs-to-html": "^0.8.3",
"e164": "0.0.5",
"echarts": "^4.0.4",
Expand All @@ -67,6 +68,7 @@
"letsencrypt-express": "^2.0.7",
"lodash": "^4.17.4",
"lodash.isarray": "^4.0.0",
"markdown-draft-js": "^0.6.2",
"marked": "^0.3.19",
"mathjax": "^2.7.0",
"mime": "^2.2.2",
Expand Down
24 changes: 10 additions & 14 deletions shared/Blog/Components/RelatedContent.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { connect } from 'react-redux'
import React, { Component } from 'react'
import { Link } from 'react-router'

class RelatedContent extends React.Component {
constructor(props) {
super(props)
}

class RelatedContent extends Component {
render() {
var { items } = this.props
if (!items) {
Expand All @@ -19,14 +13,17 @@ class RelatedContent extends React.Component {
}
return (
<div>
{items.map(function(item) {
{items.map((item, index) => {
var dest = item.dest
var title = item.title
var body = item.body
var type = item.type
if (type == 'person') {
return (
<div className="related-content-container row">
<div
className="related-content-container row"
key={item.content_id}
>
<div className="related-content-person-left col-xs-12 col-sm-4">
<img className="related-content-person-img" src={dest} />
</div>
Expand All @@ -45,7 +42,7 @@ class RelatedContent extends React.Component {
var publish_date = item.publish_date
var guid = item.guid
return (
<div className="related-content-container">
<div className="related-content-container" key={item.content_id}>
<div className="related-content-imageless-inner">
<Link to={to}>
<h3 className="related-content-h3">{title}</h3>
Expand All @@ -63,7 +60,7 @@ class RelatedContent extends React.Component {
var publish_date = item.publish_date
var guid = item.guid
return (
<div className="related-content-container">
<div className="related-content-container" key={item.content_id}>
<div className="related-content-imageless-inner">
<Link to={to}>
<h3 className="related-content-h3">{title}</h3>
Expand All @@ -76,8 +73,7 @@ class RelatedContent extends React.Component {
</div>
)
} else {
console.log('UNSUPPORTED TYPE: ' + type)
return <div className="related-content" />
return <div className="related-content" key={item.content_id} />
}
})}
</div>
Expand Down
148 changes: 148 additions & 0 deletions shared/Contributors/Forms/AddContributor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React from 'react'
import moment from 'moment'
import { isEmpty } from 'lodash'
import { Field, reduxForm } from 'redux-form'
import FormController from '../../Forms/Components/FormController/FormController'
import {
renderField,
renderSelect,
renderZip
} from '../../Forms/Components/Field'
import RichTextarea from '../../Forms/Components/RichTextarea'
import ImageUploadField from '../../Forms/Components/ImageUploadField'

const env = process.env.NODE_ENV === 'dev' ? 'dev' : 'prod'
const config = require('../../../config/config.json')
const c = config[env]

export const FORM_KEY = 'addContributor'

const validate = values => {
let errors = {}

if (isEmpty(values.prettyname)) {
errors.prettyname = 'Pretty Name field is required'
}

if (isEmpty(values.img)) {
errors.img = 'Image field is required'
}

if (isEmpty(values.author)) {
errors.author = 'Author field is required'
}

if (isEmpty(values.twitter)) {
errors.twitter = 'Author field is required'
}

if (isEmpty(values.linkedin)) {
errors.linkedin = 'Linkedin field is required'
}

if (isEmpty(values.bio)) {
errors.bio = 'Bio field is required'
}

if (isEmpty(values.sort_rank)) {
errors.sort_rank = 'Sort rank field is required'
} else if (values.sort_rank < 0) {
errors.sort_rank = 'Number should be positive'
}

return errors
}

const AddContributorForm = ({
children,
handleSubmit,
pristine,
reset,
submitting,
allowSubmit,
activeStep,
errorMessage,
ready,
recording,
stop,
review,
submit,
complete,
submittedUrl,
error,
showSubmit,
customError,
customSuccess
}) => (
<FormController
name={`addJob`}
showSubmit={showSubmit}
invalid={!allowSubmit}
submitValue={`Submit`}
handleSubmit={handleSubmit}
customError={customError}
customSuccess={customSuccess}
>
<Field
label="Pretty Name"
component={renderField}
name="prettyname"
type="text"
required
/>

<Field
label="Image"
component={renderField}
name={`img`}
required
customComponent={ImageUploadField}
bucket={c['files']['site_bucket']}
accept="image/jpeg, image/png"
/>

<Field
label="Author"
component={renderField}
name="author"
type="text"
required
/>

<Field
label="Twitter"
component={renderField}
name="twitter"
type="text"
required
/>

<Field
label="Linkedin"
component={renderField}
name="linkedin"
type="text"
required
/>

<Field
label="Bio"
component={renderField}
customComponent={RichTextarea}
name="bio"
/>

<Field
label="Sort Rank"
component={renderField}
name="sort_rank"
type="number"
required
/>
</FormController>
)

export default reduxForm({
form: FORM_KEY,
validate
})(AddContributorForm)
5 changes: 3 additions & 2 deletions shared/Forms/Components/Field/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export const renderSelect = ({
fieldWrapperClasses = '',
labelWrapperClasses = '',
inputWrapperStyles = '',
options = []
options = [],
blankOption = false
}) => {
return (
<div className={`field-container ${fieldWrapperClasses}`}>
Expand All @@ -25,7 +26,7 @@ export const renderSelect = ({
touched && invalid ? 'has-danger' : ''
}`}
>
<option value="" />
{blankOption && <option />}
{options.map(op => (
<option value={op.value} key={op.value}>
{op.label}
Expand Down
4 changes: 4 additions & 0 deletions shared/Forms/Components/FilePreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const Container = styled.div`
height: 100%;
max-width: 100%;
text-align: center;
<<<<<<< HEAD
position: relative
=======
position: relative;
>>>>>>> dev
`

const Preview = styled.img`
Expand Down
26 changes: 18 additions & 8 deletions shared/Forms/Components/RichTextarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,27 @@ const DEFAULT_TOOLBAR = {
}

export default class RichTextarea extends Component {
defaultProps = {
markdown: false
}

state = {
editorState: EditorState.createEmpty(),
value: this.props.input.value
}

encode = rawObject => {
return draftToHtml(rawObject)
}

decode = val => {
return htmlToDraft(val)
}

onChange = editorState => {
this.setState({ editorState })

const value = draftToHtml(convertToRaw(editorState.getCurrentContent()))
const value = this.encode(convertToRaw(editorState.getCurrentContent()))

this.setState({
value
Expand All @@ -45,22 +57,19 @@ export default class RichTextarea extends Component {
const { input: { value } } = this.props

const editorState = EditorState.createWithContent(
ContentState.createFromBlockArray(htmlToDraft(value))
ContentState.createFromBlockArray(this.decode(value))
)

this.setState({ value, editorState }, this.updateVal)
this.setState({ value, editorState })
}

componentWillReceiveProps(nextProps) {
if (this.props.input.value !== nextProps.input.value) {
const editorState = EditorState.createWithContent(
ContentState.createFromBlockArray(htmlToDraft(nextProps.input.value))
ContentState.createFromBlockArray(this.decode(nextProps.input.value))
)

this.setState(
{ value: nextProps.input.value, editorState },
this.updateVal
)
this.setState({ value: nextProps.input.value, editorState })
}
}

Expand All @@ -76,6 +85,7 @@ export default class RichTextarea extends Component {
editorClassName="richEditor"
onEditorStateChange={this.onChange}
onBlur={this.onBlur}
suppressContentEditableWarning={true}
toolbar={toolbar}
minHeight={minHeight}
/>
Expand Down
Loading