add Article
This commit is contained in:
parent
364706b708
commit
7072045613
52
src/App.js
52
src/App.js
@ -1,6 +1,13 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import {
|
||||||
|
createArticle,
|
||||||
|
updateArticle,
|
||||||
|
deleteArticle,
|
||||||
|
selectArticle,
|
||||||
|
} from './controllers/articles'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createTask,
|
createTask,
|
||||||
updateTask,
|
updateTask,
|
||||||
@ -20,6 +27,8 @@ import { updateProfile } from './controllers/profile'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
About,
|
About,
|
||||||
|
Articles,
|
||||||
|
UpdateArticle,
|
||||||
Tasks,
|
Tasks,
|
||||||
UpdateTask,
|
UpdateTask,
|
||||||
Profile,
|
Profile,
|
||||||
@ -39,6 +48,7 @@ const defaultState = {
|
|||||||
component: 'projects',
|
component: 'projects',
|
||||||
// TODO try to get rid of:
|
// TODO try to get rid of:
|
||||||
search: '',
|
search: '',
|
||||||
|
newArticle: '',
|
||||||
newTask: '',
|
newTask: '',
|
||||||
newProject: '',
|
newProject: '',
|
||||||
project: {},
|
project: {},
|
||||||
@ -52,6 +62,10 @@ class App extends React.Component {
|
|||||||
this.handleChange = this.handleChange.bind(this)
|
this.handleChange = this.handleChange.bind(this)
|
||||||
this.handleSubmit = this.handleSubmit.bind(this)
|
this.handleSubmit = this.handleSubmit.bind(this)
|
||||||
|
|
||||||
|
this.createArticle = createArticle.bind(this)
|
||||||
|
this.updateArticle = updateArticle.bind(this)
|
||||||
|
this.deleteArticle = deleteArticle.bind(this)
|
||||||
|
|
||||||
this.createTask = createTask.bind(this)
|
this.createTask = createTask.bind(this)
|
||||||
this.updateTask = updateTask.bind(this)
|
this.updateTask = updateTask.bind(this)
|
||||||
this.deleteTask = deleteTask.bind(this)
|
this.deleteTask = deleteTask.bind(this)
|
||||||
@ -62,10 +76,21 @@ class App extends React.Component {
|
|||||||
|
|
||||||
this.updateProfile = updateProfile.bind(this)
|
this.updateProfile = updateProfile.bind(this)
|
||||||
|
|
||||||
|
this.selectArticle = selectArticle.bind(this)
|
||||||
this.selectTask = selectTask.bind(this)
|
this.selectTask = selectTask.bind(this)
|
||||||
this.selectProject = selectProject.bind(this)
|
this.selectProject = selectProject.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchArticles() {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(API + '/api/articles')
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
this.setState({ error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fetchTasks() {
|
async fetchTasks() {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get(API + '/api/tasks')
|
const { data } = await axios.get(API + '/api/tasks')
|
||||||
@ -87,9 +112,10 @@ class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
|
const articles = await this.fetchArticles()
|
||||||
const tasks = await this.fetchTasks()
|
const tasks = await this.fetchTasks()
|
||||||
const projects = await this.fetchProjects()
|
const projects = await this.fetchProjects()
|
||||||
await this.setState({ loading: false, tasks, projects })
|
await this.setState({ loading: false, articles, tasks, projects })
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -139,6 +165,26 @@ class App extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
renderArticles() {
|
||||||
|
return (<Articles
|
||||||
|
navigate={this.navigate}
|
||||||
|
handleChange={this.handleChange}
|
||||||
|
createArticle={this.createArticle}
|
||||||
|
selectArticle={this.selectArticle}
|
||||||
|
deleteArticle={this.deleteArticle}
|
||||||
|
{...this.state}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
renderUpdateArticle() {
|
||||||
|
return (<UpdateArticle
|
||||||
|
handleChange={this.handleChange}
|
||||||
|
updateArticle={this.updateArticle}
|
||||||
|
navigate={this.navigate}
|
||||||
|
{...this.state}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
renderProjects() {
|
renderProjects() {
|
||||||
return (
|
return (
|
||||||
<Projects
|
<Projects
|
||||||
@ -217,6 +263,10 @@ class App extends React.Component {
|
|||||||
? this.renderLoading()
|
? this.renderLoading()
|
||||||
: this.state.error
|
: this.state.error
|
||||||
? this.renderError()
|
? this.renderError()
|
||||||
|
: this.state.component === 'articles'
|
||||||
|
? this.renderArticles()
|
||||||
|
: this.state.component === 'article'
|
||||||
|
? this.renderUpdateArticle()
|
||||||
: this.state.component === 'tasks'
|
: this.state.component === 'tasks'
|
||||||
? this.renderTasks(filtered, completed)
|
? this.renderTasks(filtered, completed)
|
||||||
: this.state.component === 'task'
|
: this.state.component === 'task'
|
||||||
|
49
src/components/articles.js
Normal file
49
src/components/articles.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function Articles(props) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 className="mt-4">Articles</h3>
|
||||||
|
<ul className="list-group">
|
||||||
|
{props.articles &&
|
||||||
|
props.articles.map(article => (
|
||||||
|
<li className="list-group-item" key={article.id}>
|
||||||
|
<button
|
||||||
|
className="btn btn-outline-danger mr-1"
|
||||||
|
onClick={() => props.deleteArticle(article.id)}
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn ml-1"
|
||||||
|
onClick={() => props.selectArticle(article.id)}
|
||||||
|
>
|
||||||
|
{article.title}{' '}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<li className="list-group-item">
|
||||||
|
<form className="form-group row" onSubmit={props.createArticle}>
|
||||||
|
<input
|
||||||
|
className="form-control col input-sm"
|
||||||
|
placeholder="Create Article"
|
||||||
|
name="newArticle"
|
||||||
|
value={props.newArticle}
|
||||||
|
onChange={props.handleChange}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="form-control col col-sm-2 ml-1 btn btn-primary"
|
||||||
|
onClick={props.createArticle}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Articles
|
@ -1,5 +1,7 @@
|
|||||||
export { default as Navbar } from './navbar'
|
export { default as Navbar } from './navbar'
|
||||||
export { default as About } from './about'
|
export { default as About } from './about'
|
||||||
|
export { default as Articles } from './articles'
|
||||||
|
export { default as UpdateArticle } from './update-article'
|
||||||
export { default as Tasks } from './tasks'
|
export { default as Tasks } from './tasks'
|
||||||
export { default as UpdateTask } from './update-task'
|
export { default as UpdateTask } from './update-task'
|
||||||
export { default as Profile } from './profile'
|
export { default as Profile } from './profile'
|
||||||
|
@ -23,13 +23,23 @@ function Navbar(props) {
|
|||||||
</button>
|
</button>
|
||||||
<div className="collapse navbar-collapse" id="navbarText">
|
<div className="collapse navbar-collapse" id="navbarText">
|
||||||
<ul className="navbar-nav mr-auto">
|
<ul className="navbar-nav mr-auto">
|
||||||
|
<li
|
||||||
|
className={`nav-item ${
|
||||||
|
props.component === 'about' ? 'active' : ''
|
||||||
|
}`}
|
||||||
|
onClick={() => props.navigate('articles')}
|
||||||
|
>
|
||||||
|
<a className="nav-link" href="#articles">
|
||||||
|
Articles
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
className={`nav-item ${
|
className={`nav-item ${
|
||||||
props.component === 'project' ? 'active' : ''
|
props.component === 'project' ? 'active' : ''
|
||||||
}`}
|
}`}
|
||||||
onClick={() => props.navigate('project')}
|
onClick={() => props.navigate('projects')}
|
||||||
>
|
>
|
||||||
<a className="nav-link" href="#project">
|
<a className="nav-link" href="#projects">
|
||||||
Projects
|
Projects
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
76
src/components/update-article.js
Normal file
76
src/components/update-article.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
class UpdateArticle extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
const article = props.articles.find(t => t.id === props.selectedArticleId)
|
||||||
|
this.state = article
|
||||||
|
this.handleChange = this.handleChange.bind(this)
|
||||||
|
|
||||||
|
if (!props.selectedArticleId) {
|
||||||
|
props.navigate('articles')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(e) {
|
||||||
|
this.setState({ [e.target.name]: e.target.value })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span onClick={() => this.props.navigate('articles')}>« back</span>
|
||||||
|
<form>
|
||||||
|
<h2 className="form-group row">Article {this.state.id}</h2>
|
||||||
|
<div className="form-group row">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="form-control mb-1"
|
||||||
|
name="title"
|
||||||
|
value={this.state.title}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group row">
|
||||||
|
<textarea
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
name="text"
|
||||||
|
rows="25"
|
||||||
|
value={this.state.text || ""}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group row">
|
||||||
|
<label htmlFor="createdAt" className="col-sm-2 col-form-label">
|
||||||
|
Created:
|
||||||
|
</label>
|
||||||
|
<div className="col-sm-10">
|
||||||
|
<input
|
||||||
|
className="form-control"
|
||||||
|
name="createdAt"
|
||||||
|
value={this.state.createdAt}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group row">
|
||||||
|
<div className="col-sm-10">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={e => this.props.updateArticle(e, this.state)}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UpdateArticle
|
85
src/controllers/articles.js
Normal file
85
src/controllers/articles.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
const API = process.env.REACT_APP_API || 'http://localhost:1337'
|
||||||
|
|
||||||
|
export async function createArticle(e) {
|
||||||
|
e.preventDefault()
|
||||||
|
if (this.state.newArticle === '') {
|
||||||
|
alert('You forgot the title.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const article = { title: this.state.newArticle }
|
||||||
|
try {
|
||||||
|
const { data, error } = await axios.post(API + '/api/articles', article)
|
||||||
|
if (error) {
|
||||||
|
alert(`Received error when creating article ${article.name}: ${error}`)
|
||||||
|
} else if (data.id) {
|
||||||
|
this.setState({
|
||||||
|
articles: this.state.articles.concat(data),
|
||||||
|
newArticle: '',
|
||||||
|
})
|
||||||
|
console.log(`Added article: `, data)
|
||||||
|
} else {
|
||||||
|
alert(`Failed to add article '${article}'.`)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(`Failed to add article '${this.state.newArticle}'.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function selectArticle(selectedArticleId) {
|
||||||
|
this.setState({ selectedArticleId })
|
||||||
|
this.navigate('article')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateArticle(e, updatedArticle) {
|
||||||
|
e.preventDefault()
|
||||||
|
const oldArticle = this.state.articles.find(t => t.id === updatedArticle.id)
|
||||||
|
if (JSON.stringify(oldArticle) === JSON.stringify(updatedArticle)) {
|
||||||
|
this.navigate('articles')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { data, error } = await axios.put(
|
||||||
|
API + `/api/articles/${oldArticle.id}`,
|
||||||
|
updatedArticle,
|
||||||
|
)
|
||||||
|
if (error) {
|
||||||
|
alert('Received error when updating article: ', error)
|
||||||
|
} else if (data.title) {
|
||||||
|
const oldArticles = this.state.articles.filter(t => t.id !== updatedArticle.id)
|
||||||
|
this.setState({ articles: oldArticles.concat(updatedArticle) })
|
||||||
|
console.log('Successfully updated article:', data)
|
||||||
|
this.navigate('articles')
|
||||||
|
} else {
|
||||||
|
console.log('Received malformed data when updating article: ', data)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(`Updating article failed: ${e}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteArticle(id) {
|
||||||
|
const article = this.state.articles.find(p => p.id === id)
|
||||||
|
if (!article.id) {
|
||||||
|
alert(`Could not find article with id ${id}.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { data, error } = await axios.post(
|
||||||
|
API + `/api/articles/${article.id}/delete`,
|
||||||
|
)
|
||||||
|
if (error) {
|
||||||
|
alert(`Received error when deleting article ${article.title}: ${error}`)
|
||||||
|
} else if (data.title) {
|
||||||
|
console.log('Deleted article:', data)
|
||||||
|
this.setState({
|
||||||
|
articles: this.state.articles.filter(p => p.id !== article.id),
|
||||||
|
})
|
||||||
|
this.navigate('articles')
|
||||||
|
} else {
|
||||||
|
alert(`Failed to delete article '${article.title}'.`)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert(`Failed to delete article '${article.title}': ${e}`)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user