diff --git a/functions/todos-delete-batch.js b/functions/todos-delete-batch.js new file mode 100644 index 0000000..3e0479c --- /dev/null +++ b/functions/todos-delete-batch.js @@ -0,0 +1,32 @@ +import faunadb from 'faunadb' +import getId from './utils/getId' + +const q = faunadb.query +const client = new faunadb.Client({ + secret: process.env.FAUNADB_SECRET +}) + +exports.handler = (event, context, callback) => { + const data = JSON.parse(event.body) + console.log('data', data) + console.log("Function `todo-delete-batch` invoked", data.ids) + // construct batch query from IDs + const deleteAllCompletedTodoQuery = data.ids.map((id) => { + return q.Delete(q.Ref(`classes/todos/${id}`)) + }) + // Hit fauna with the query to delete the completed items + return client.query(deleteAllCompletedTodoQuery) + .then((response) => { + console.log("success", response) + return callback(null, { + statusCode: 200, + body: JSON.stringify(response) + }) + }).catch((error) => { + console.log("error", error) + return callback(null, { + statusCode: 400, + body: JSON.stringify(error) + }) + }) +} diff --git a/src/App.js b/src/App.js index d0fd76b..049d1ab 100644 --- a/src/App.js +++ b/src/App.js @@ -158,13 +158,49 @@ export default class App extends Component { }) } } + clearCompleted = () => { + const { todos } = this.state + + // Optimistically remove todos from UI + const data = todos.reduce((acc, current) => { + if (current.data.completed) { + // save item being removed for rollback + acc.completedTodoIds = acc.completedTodoIds.concat(getTodoId(current)) + return acc + } + // filter deleted todo out of the todos list + acc.optimisticState = acc.optimisticState.concat(current) + return acc + }, { + completedTodoIds: [], + optimisticState: [] + }) + + // only set state if completed todos exist + if (!data.completedTodoIds.length) { + alert('Please check off some todos to batch remove them') + this.closeModal() + return false + } + + this.setState({ + todos: data.optimisticState + }, () => { + api.batchDelete(data.completedTodoIds).then(() => { + console.log(`Batch removal complete`, data.completedTodoIds) + this.closeModal() + }).catch((e) => { + console.log('An API error occurred', e) + }) + }) + + } closeModal = (e) => { this.setState({ showMenu: false }) } openModal = () => { - console.log('settings') this.setState({ showMenu: true }) @@ -254,7 +290,11 @@ export default class App extends Component { {this.renderTodos()} - + ) } diff --git a/src/components/SettingsIcon/index.js b/src/components/SettingsIcon/index.js index 79f99ac..1a48624 100644 --- a/src/components/SettingsIcon/index.js +++ b/src/components/SettingsIcon/index.js @@ -4,7 +4,7 @@ import styles from './SettingIcon.css' // eslint-disable-line const SettingIcon = (props) => { const className = props.className || '' return ( - + diff --git a/src/components/SettingsMenu/index.js b/src/components/SettingsMenu/index.js index a1edaf3..a22ad49 100644 --- a/src/components/SettingsMenu/index.js +++ b/src/components/SettingsMenu/index.js @@ -20,6 +20,7 @@ export default class Menu extends Component { const deleteConfirm = window.confirm("Are you sure you want to clear all completed todos?"); if (deleteConfirm) { console.log('delete') + this.props.handleClearCompleted() } } render() { @@ -28,7 +29,9 @@ export default class Menu extends Component { return ( - ❌ + + ❌ + Settings diff --git a/src/utils/api.js b/src/utils/api.js index 1078dd1..b609b68 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -34,9 +34,21 @@ const deleteTodo = (todoId) => { }) } +const batchDeleteTodo = (todoIds) => { + return fetch(`/.netlify/functions/todos-delete-batch`, { + body: JSON.stringify({ + ids: todoIds + }), + method: 'POST' + }).then(response => { + return response.json() + }) +} + export default { create: create, readAll: readAll, update: update, - delete: deleteTodo + delete: deleteTodo, + batchDelete: batchDeleteTodo }