fix: Add error handling to Settings form

This commit adds error handling to the settings form in the Settings.vue page. A new 'errors' object has been introduced to capture and display errors returned from the API. The onSubmit event also has been modified for handling a try/catch block for potential API errors.
The associated unit test was updated to ensure proper behavior when an API error is returned.
This improvement aims to provide a better user experience by clearly communicating issues with the user's changes.

close #58
This commit is contained in:
mutoe 2023-09-08 16:53:38 +08:00
parent 1ba77588f1
commit ece4466b7a
No known key found for this signature in database
GPG Key ID: FEE78A0836900C9C
2 changed files with 35 additions and 7 deletions

View File

@ -1,3 +1,4 @@
import userEvent from '@testing-library/user-event'
import { fireEvent, render, waitFor } from '@testing-library/vue' import { fireEvent, render, waitFor } from '@testing-library/vue'
import { describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import { router } from 'src/router.ts' import { router } from 'src/router.ts'
@ -80,4 +81,16 @@ describe('# Settings Page', () => {
} }
`) `)
}) })
it('should display error message when api returned some errors', async () => {
server.use(['PUT', '/api/user', 400, { errors: { username: ['has already been taken'] } }])
const { getByRole, getByPlaceholderText, getByText } = render(Settings, renderOptions({
initialState: { user: { user: fixtures.user } },
}))
await userEvent.type(getByPlaceholderText('Your name'), 'new username')
await userEvent.click(getByRole('button', { name: 'Update Settings' }))
expect(getByText('username has already been taken')).toBeInTheDocument()
})
}) })

View File

@ -7,6 +7,12 @@
Your Settings Your Settings
</h1> </h1>
<ul class="error-messages">
<li v-for="(error, field) in errors" :key="field">
{{ field }} {{ error ? error[0] : '' }}
</li>
</ul>
<form @submit.prevent="onSubmit"> <form @submit.prevent="onSubmit">
<fieldset> <fieldset>
<fieldset class="form-group"> <fieldset class="form-group">
@ -75,22 +81,31 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, reactive } from 'vue' import { computed, onMounted, reactive, ref } from 'vue'
import { routerPush } from 'src/router' import { routerPush } from 'src/router'
import { api } from 'src/services' import { api, isFetchError } from 'src/services'
import type { UpdateUser } from 'src/services/api' import type { UpdateUser } from 'src/services/api'
import { useUserStore } from 'src/store/user' import { useUserStore } from 'src/store/user'
const form: UpdateUser = reactive({}) const form: UpdateUser = reactive({})
const userStore = useUserStore() const userStore = useUserStore()
const errors = ref()
const onSubmit = async () => { const onSubmit = async () => {
// eslint-disable-next-line unicorn/no-array-reduce errors.value = {}
const filteredForm = Object.entries(form).reduce((form, [k, v]) => v === null ? form : Object.assign(form, { [k]: v }), {})
const userData = await api.user.updateCurrentUser({ user: filteredForm }).then(res => res.data.user) try {
userStore.updateUser(userData) // eslint-disable-next-line unicorn/no-array-reduce
await routerPush('profile', { username: userData.username }) const filteredForm = Object.entries(form).reduce((form, [k, v]) => v === null ? form : Object.assign(form, { [k]: v }), {})
const userData = await api.user.updateCurrentUser({ user: filteredForm }).then(res => res.data.user)
userStore.updateUser(userData)
await routerPush('profile', { username: userData.username })
} catch (error) {
if (isFetchError(error)) {
errors.value = error.error?.errors
}
}
} }
const onLogout = async () => { const onLogout = async () => {