import React from 'react' import axios from 'axios' import { About, Tasks, UpdateTask, Profile, Projects, Project, Navbar, } from './components' const api = process.env.REACT_APP_API || 'http://localhost:1337' //console.log(process.env) console.log('Using api at ' + api) const defaultState = { user: { name: 'Scott' }, loading: true, tasks: [], search: '', newTask: '', newProject: '', project: {}, projects: [], component: 'projects', } class App extends React.Component { constructor() { super() this.state = defaultState this.navigate = this.navigate.bind(this) this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) this.addTask = this.addTask.bind(this) this.deleteTask = this.deleteTask.bind(this) this.completeTask = this.completeTask.bind(this) this.createProject = this.createProject.bind(this) this.selectProject = this.selectProject.bind(this) this.selectTask = this.selectTask.bind(this) this.updateTask = this.updateTask.bind(this) this.deleteProject = this.deleteProject.bind(this) } async fetchTasks() { try { const { data } = await axios.get(api + '/api/tasks') return data } catch (error) { console.log(error) this.setState({ error }) } } async fetchProjects() { try { const { data } = await axios.get(api + '/api/projects') return data } catch (error) { console.log(error) this.setState({ error }) } } async fetchData() { const tasks = await this.fetchTasks() const projects = await this.fetchProjects() await this.setState({ loading: false, tasks, projects }) } componentDidMount() { this.fetchData() } navigate(component) { this.setState({ component }) } handleChange(e) { this.setState({ [e.target.name]: e.target.value }) } handleSubmit(e) { e.preventDefault() this.setState({ search: '' }) } async addTask(e) { e.preventDefault() const newTask = { desc: this.state.newTask, projectName: this.state.projects.find( p => p.id === this.state.selectedProjectId, )['name'], // TODO // the backend expects projectName because it creates the project on the fly if none exists with that name // this feature comes at the price that there can't be two independent projects with the same name // which could be handy if users want to have private projects } if (newTask.desc === '') { alert('Task description is empty.') return } else if (!newTask.projectName) { alert('Select a project for new task.') return } try { console.log('Adding task: ', newTask) const { data, error } = await axios.post(api + '/api/tasks', newTask) if (error) { alert('Received error when adding task: ', error) } else if (data.desc && data.projectId) { console.log('Successfully added task:', data) this.setState({ tasks: this.state.tasks.concat(data), newTask: '' }) } else { console.log('Received malformed data for added task: ', data) } } catch (e) { alert(`Failed to add task: ${e}`) } } async updateTask(e, updatedTask) { e.preventDefault() console.log('updatedTask:', updatedTask) const oldTask = this.state.tasks.find( t => t.id === this.state.selectedTaskId, ) if (JSON.stringify(oldTask) === JSON.stringify(updatedTask)) return try { const { data, error } = await axios.put( api + `/api/tasks/${oldTask.id}`, updatedTask, ) if (error) { alert('Received error when updating task: ', error) } else if (data.desc && data.projectId) { const oldTasks = this.state.tasks.filter(t => t.id !== updatedTask.id) this.setState({ tasks: oldTasks.concat(updatedTask) }) console.log('Successfully updated task:', data) } else { console.log('Received malformed data when updating task: ', data) } } catch (e) { alert(`Updating task failed: ${e}`) } } async deleteTask(id) { this.setState({ tasks: this.state.tasks.filter(t => t.id !== id) }) try { const { data, error } = await axios.post(api + `/api/tasks/${id}/delete`) if (error) { alert('Received error when deleting task: ', error) } else { console.log('Successfully deleted task: ', data) this.setState({ tasks: this.state.tasks.filter(t => t.id !== data.id), newTask: '', }) } } catch (e) { alert('Failed to delete task: ', e) } } async completeTask(id) { const task = this.state.tasks.find(t => t.id === id) if (!task.id) { alert(`Couldn't find task with id ${id}`) return } try { task.completed = !task.completed const { data, error } = await axios.put( api + `/api/tasks/${task.id}`, task, ) if (error) { alert(`Received error when completing task ${task.desc}: ${error}`) } else if (data.id) { const otherTasks = this.state.tasks.filter(t => t.id !== id) this.setState({ tasks: otherTasks.concat(data) }) console.log(`Completed task:`, data) } else { alert(`Failed to complete task with id ${id}`) } } catch (e) { alert(`Failed to complete task ${task.desc}: ${e}`) } } selectTask(id) { this.setState({ selectedTaskId: id }) this.navigate('task') } async createProject(e) { e.preventDefault() const project = { name: this.state.newProject } try { const { data, error } = await axios.post(api + '/api/projects', project) if (error) { alert(`Received error when creating project ${project.name}: ${error}`) } else if (data.id) { this.setState({ projects: this.state.projects.concat(data), newProject: '', }) console.log(`Added project: `, data) } else { alert(`Failed to add project '${project}'.`) } } catch (e) { alert(`Failed to add project '${this.state.newProject}'.`) } } selectProject(selectedProjectId) { this.setState({ selectedProjectId }) this.navigate('project') } async deleteProject(id) { const project = this.state.projects.find(p => p.id === id) if (!project.id) { alert(`Could not find project with id ${id}.`) return } const tasks = this.state.tasks.filter(t => t.projectId === project.id) if (tasks.length > 0) { if ( window.confirm( `Project ${project.name} has ${tasks.length} tasks. Are you sure?`, ) ) { this.setState({ tasks: this.state.tasks.filter(t => t.projectId !== project.id), }) console.log( `Removed ${tasks.length} tasks of project '${project.name}'.`, ) } else { return } } try { const { data, error } = await axios.post( api + `/api/projects/${project.id}/delete`, ) if (error) { alert(`Received error when deleting project ${project.name}: ${error}`) } else if (data.name) { console.log('Deleted project:', data) this.setState({ projects: this.state.projects.filter(p => p.id !== project.id), }) this.navigate('projects') } else { alert(`Failed to delete project '${project.name}'.`) } } catch (e) { alert(`Failed to delete project '${project.name}': ${e}`) } } renderLoading() { return
Loading...
} renderError() { return
Something went wrong. Please try again.
} renderProfile() { return } renderProjects() { return ( ) } renderProject() { return ( ) } renderAbout() { return } renderTasks(filtered, completed) { return ( ) } renderUpdateTask() { return ( ) } render() { //console.log(this.state) // TODO refactor task filtering const completed = (this.state.tasks && this.state.tasks.filter(task => task.completed === true)) || [] const filtered = (this.state.tasks && this.state.tasks.filter( task => task.completed !== true && this.state.search === task.desc.slice(0, this.state.search.length), )) || [] const renderComponent = () => this.state.loading ? this.renderLoading() : this.state.component === 'tasks' ? this.renderTasks(filtered, completed) : this.state.component === 'task' ? this.renderUpdateTask() : this.state.component === 'about' ? this.renderAbout() : this.state.component === 'profile' ? this.renderProfile() : this.state.component === 'projects' ? this.renderProjects() : this.state.component === 'project' ? this.renderProject() : this.renderError() return (
{renderComponent()}
) } } export default App