Handle errors on JS side in todo_app

pull/5/head
Dmitry Ignatiev 12 months ago
parent 158184e0a6
commit 20e07ea032

@ -1,7 +1,5 @@
# todo-ui # todo-ui
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup ## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).

@ -0,0 +1,38 @@
<template>
<div class="toast fade" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="5000" ref="elt">
<div class="toast-header text-white bg-danger">
<strong class="me-auto">Error</strong>
<small class=""></small>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
<div v-for="msg in messages" :key="msg">
{{ msg }}
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { Toast } from 'bootstrap'
defineProps({
messages: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['closed'])
const elt = ref()
let toastObject = null
onMounted(() => {
toastObject = new Toast(elt.value)
toastObject.show()
elt.value.addEventListener("hidden.bs.toast", () => {
emit('closed')
})
})
</script>

@ -78,18 +78,24 @@
</div> </div>
</div> </div>
</div> </div>
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<ErrorToast v-for="item in errors" :key="item" :messages="item.messages" @closed="removeToast(item)" />
</div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, computed } from 'vue' import { ref, onMounted, computed, reactive } from 'vue'
import { onBeforeRouteUpdate, useRoute, RouterLink } from 'vue-router' import { onBeforeRouteUpdate, useRoute, RouterLink } from 'vue-router'
import svc from '../services/todoService' import svc from '../services/todoService'
import { useDebouncedRef } from '../services/composables' import { useDebouncedRef } from '../services/composables'
import TodoItem from './TodoItem.vue'; import TodoItem from './TodoItem.vue';
import ErrorToast from './ErrorToast.vue';
const route = useRoute() const route = useRoute()
const errors = reactive([])
const totalCount = ref(0) const totalCount = ref(0)
const left = ref(0) const left = ref(0)
const search = ref() const search = ref()
@ -111,6 +117,41 @@ const completedFilter = computed(() => {
}) })
const isEmpty = computed(() => !totalCount.value) const isEmpty = computed(() => !totalCount.value)
function handleError(e) {
const messages = []
console.log(e)
const response = e.response
if (response) {
const status = response.status
if(status) {
if(status == 400) {
messages.push('API Error. HTTP 400: Bad request')
} else if (status == 401) {
messages.push('API Error. HTTP 401: Unauthorized')
} else if (status == 403) {
messages.push('API Error. HTTP 403: Forbidden')
} else if (status == 404) {
messages.push('API Error. HTTP 404: Not found')
} else if (status == 500) {
messages.push('API Error. HTTP 500: Internal server error')
} else {
messages.push(`API Error. HTTP ${status}`)
}
} else {
messages.push('API Error. Network error')
}
} else if (e.code == 'ERR_NETWORK') {
messages.push('API Error: Connection refused')
} else if (e.code == 'ECONNABORTED' || e.code == 'ETIMEDOUT') {
messages.push('API Error: Timeout')
} else if (e.code == 'ERR_BAD_RESPONSE') {
messages.push('API Error: Bad response')
} else {
messages.push(`Unidentified error: ${e}`)
}
errors.push({ messages })
}
async function updateStatus() { async function updateStatus() {
try { try {
const status = await svc.status() const status = await svc.status()
@ -122,7 +163,7 @@ async function updateStatus() {
isCompleted.value = false isCompleted.value = false
} }
} catch (e) { } catch (e) {
console.log(e) handleError(e)
} }
} }
@ -137,7 +178,7 @@ async function refresh() {
totalCount.value = rv.totalCount totalCount.value = rv.totalCount
await updateStatus() await updateStatus()
} catch (e) { } catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
@ -152,7 +193,7 @@ async function deleteItem(id) {
}) })
await updateStatus() await updateStatus()
} catch (e) { } catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
@ -173,7 +214,7 @@ async function onSubmit() {
await updateStatus() await updateStatus()
} }
catch (e) { catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
@ -197,7 +238,7 @@ async function onToggle(todo) {
} }
await updateStatus() await updateStatus()
} catch (e) { } catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
@ -223,7 +264,7 @@ async function onToggleAll() {
await updateStatus() await updateStatus()
} }
catch (e) { catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
@ -234,13 +275,20 @@ async function deleteCompleted() {
try { try {
await svc.deleteCompleted(); await svc.deleteCompleted();
} catch (e) { } catch (e) {
console.log(e) handleError(e)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }
await refresh() await refresh()
} }
function removeToast(item) {
const idx = errors.findIndex(x => x == item)
if (idx >= 0) {
errors.splice(idx, 1)
}
}
onMounted(refresh) onMounted(refresh)
onBeforeRouteUpdate(async to => { onBeforeRouteUpdate(async to => {

Loading…
Cancel
Save