diff --git a/src/App.js b/src/App.js index e6fa053..d944a7f 100644 --- a/src/App.js +++ b/src/App.js @@ -73,7 +73,6 @@ class App extends React.Component { } handleSubmit(e) { e.preventDefault() - console.log('Search term: ', this.state.search) this.setState({ search: '' }) } @@ -81,7 +80,8 @@ class App extends React.Component { e.preventDefault() const newTask = { desc: this.state.newTask, - projectName: this.state.selectedProject, + 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 @@ -105,7 +105,7 @@ class App extends React.Component { console.log('Received malformed data for added task: ', data) } } catch (e) { - alert('Failed to add task: ', e) + alert(`Failed to add task: ${e}`) } } async deleteTask(id) { @@ -122,23 +122,48 @@ class App extends React.Component { alert('Failed to delete task: ', e) } } - completeTask(id) { - const otherTasks = this.state.tasks.filter(t => t.id !== id) - const completedTask = this.state.tasks.find(t => t.id === id) - completedTask.completed = !completedTask.completed - console.log(completedTask) - this.setState({ tasks: otherTasks.concat(completedTask) }) + 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}`) + } } - createProject(e) { + async createProject(e) { e.preventDefault() - this.setState({ - projects: this.state.projects.concat({ - id: this.state.projects.length, - name: this.state.newProject, - }), - newProject: '', - }) + 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) { @@ -146,9 +171,34 @@ class App extends React.Component { this.navigate('project') } async deleteProject(id) { - //this.setState({ projects: this.state.projects.filter(p => p.id !== id) }) - await axios.post(`/api/projects/${id}/delete`) - // TODO: some delete success function + 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() { @@ -182,6 +232,7 @@ class App extends React.Component { addTask={this.addTask} completeTask={this.completeTask} deleteTask={this.deleteTask} + navigate={this.navigate} {...this.state} /> ) @@ -205,13 +256,18 @@ class App extends React.Component { ) } render() { - console.log(this.state) - const completed = this.state.tasks.filter(task => task.completed === true) - const filtered = this.state.tasks.filter( - task => - task.completed !== true && - this.state.search === task.desc.slice(0, this.state.search.length), - ) + //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 diff --git a/src/components/add-task.js b/src/components/add-task.js index 8445512..0e1e7f8 100644 --- a/src/components/add-task.js +++ b/src/components/add-task.js @@ -11,22 +11,29 @@ function FilterTask(props) { value={props.newTask} onChange={props.handleChange} /> - {props.component === 'project' ? null : ( + {props.component === 'project' ? ( + '' + ) : ( )} - + ) diff --git a/src/components/project.js b/src/components/project.js index 8e5eda7..0b5aec6 100644 --- a/src/components/project.js +++ b/src/components/project.js @@ -2,20 +2,23 @@ import React from 'react' import Tasks from './tasks' function Project(props) { + if (!props.selectedProjectId) { + props.navigate('projects') + return null + } + // TODO re-fetch project list if no project name is found instead of setting 'Default' const projectName = - props.projects.find(p => p.id === props.selectedProjectId).name || 'Default' - const filtered = props.tasks.filter( - t => t.projectId === props.selectedProjectId && !t.completed - ) + props.projects.find(p => p.id === props.selectedProjectId)['name'] || 'Default' + + const filtered = props.tasks.filter(t => t.projectId === props.selectedProjectId && !t.completed) const completed = props.tasks.filter( - t => - (t.projectId === props.selectedProjectId && t.completed === true) || null + t => (t.projectId === props.selectedProjectId && t.completed === true) || null, ) return (