Refactor forms to use EntityEditForm component; enhance styles and improve structure
Some checks failed
Gitea Actions Demo / build-and-push (push) Failing after 6s
Some checks failed
Gitea Actions Demo / build-and-push (push) Failing after 6s
This commit is contained in:
@@ -1,56 +1,35 @@
|
||||
<template>
|
||||
<div class="child-edit-view">
|
||||
<h2>{{ isEdit ? 'Edit Child' : 'Create Child' }}</h2>
|
||||
<div v-if="loading" class="loading-message">Loading child...</div>
|
||||
<form v-else @submit.prevent="submit" class="child-edit-form">
|
||||
<div class="group">
|
||||
<label for="child-name">Name</label>
|
||||
<input type="text" id="child-name" ref="nameInput" v-model="name" required maxlength="64" />
|
||||
</div>
|
||||
<div class="group">
|
||||
<label for="child-age">Age</label>
|
||||
<input id="child-age" v-model.number="age" type="number" min="0" max="120" required />
|
||||
</div>
|
||||
<div class="group">
|
||||
<label for="child-image">Image</label>
|
||||
<ImagePicker
|
||||
id="child-image"
|
||||
v-model="selectedImageId"
|
||||
:image-type="1"
|
||||
@add-image="onAddImage"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
<div class="actions">
|
||||
<button type="button" class="btn btn-secondary" @click="onCancel" :disabled="loading">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
{{ isEdit ? 'Save' : 'Create' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<EntityEditForm
|
||||
entityLabel="Child"
|
||||
:fields="fields"
|
||||
:initialData="initialData"
|
||||
:isEdit="isEdit"
|
||||
:loading="loading"
|
||||
:error="error"
|
||||
@submit="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
@add-image="handleAddImage"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed, nextTick } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ImagePicker from '@/components/utils/ImagePicker.vue'
|
||||
import '@/assets/edit-forms.css'
|
||||
import EntityEditForm from '../shared/EntityEditForm.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
// Accept id as a prop for edit mode
|
||||
const props = defineProps<{ id?: string }>()
|
||||
|
||||
const isEdit = computed(() => !!props.id)
|
||||
const name = ref('')
|
||||
const age = ref<number | null>(null)
|
||||
const selectedImageId = ref<string | null>(null)
|
||||
|
||||
const fields = [
|
||||
{ name: 'name', label: 'Name', type: 'text', required: true, maxlength: 64 },
|
||||
{ name: 'age', label: 'Age', type: 'number', required: true, min: 0, max: 120 },
|
||||
{ name: 'image_id', label: 'Image', type: 'image', imageType: 1 },
|
||||
]
|
||||
|
||||
const initialData = ref({ name: '', age: null, image_id: null })
|
||||
const localImageFile = ref<File | null>(null)
|
||||
const nameInput = ref<HTMLInputElement | null>(null)
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
@@ -61,36 +40,34 @@ onMounted(async () => {
|
||||
const resp = await fetch(`/api/child/${props.id}`)
|
||||
if (!resp.ok) throw new Error('Failed to load child')
|
||||
const data = await resp.json()
|
||||
name.value = data.name ?? ''
|
||||
age.value = Number(data.age) ?? null
|
||||
selectedImageId.value = data.image_id ?? null
|
||||
initialData.value = {
|
||||
name: data.name ?? '',
|
||||
age: Number(data.age) ?? null,
|
||||
image_id: data.image_id ?? null,
|
||||
}
|
||||
} catch (e) {
|
||||
error.value = 'Could not load child.'
|
||||
} finally {
|
||||
loading.value = false
|
||||
await nextTick()
|
||||
nameInput.value?.focus()
|
||||
}
|
||||
} else {
|
||||
await nextTick()
|
||||
nameInput.value?.focus()
|
||||
}
|
||||
})
|
||||
|
||||
function onAddImage({ id, file }: { id: string; file: File }) {
|
||||
function handleAddImage({ id, file }: { id: string; file: File }) {
|
||||
if (id === 'local-upload') {
|
||||
localImageFile.value = file
|
||||
}
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
let imageId = selectedImageId.value
|
||||
async function handleSubmit(form: any) {
|
||||
let imageId = form.image_id
|
||||
error.value = null
|
||||
if (!name.value.trim()) {
|
||||
if (!form.name.trim()) {
|
||||
error.value = 'Child name is required.'
|
||||
return
|
||||
}
|
||||
if (age.value === null || age.value < 0) {
|
||||
if (form.age === null || form.age < 0) {
|
||||
error.value = 'Age must be a non-negative number.'
|
||||
return
|
||||
}
|
||||
@@ -111,7 +88,7 @@ const submit = async () => {
|
||||
const data = await resp.json()
|
||||
imageId = data.id
|
||||
} catch (err) {
|
||||
alert('Failed to upload image.')
|
||||
error.value = 'Failed to upload image.'
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
@@ -125,8 +102,8 @@ const submit = async () => {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: name.value,
|
||||
age: age.value,
|
||||
name: form.name,
|
||||
age: form.age,
|
||||
image_id: imageId,
|
||||
}),
|
||||
})
|
||||
@@ -135,8 +112,8 @@ const submit = async () => {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: name.value,
|
||||
age: age.value,
|
||||
name: form.name,
|
||||
age: form.age,
|
||||
image_id: imageId,
|
||||
}),
|
||||
})
|
||||
@@ -144,14 +121,12 @@ const submit = async () => {
|
||||
if (!resp.ok) throw new Error('Failed to save child')
|
||||
await router.push({ name: 'ParentChildrenListView' })
|
||||
} catch (err) {
|
||||
alert('Failed to save child.')
|
||||
error.value = 'Failed to save child.'
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
function handleCancel() {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
Reference in New Issue
Block a user