refactor(front): extract shared utils and rewire pages
This commit is contained in:
@@ -246,6 +246,16 @@ const emitSelection = (ids: string[]) => {
|
||||
emit('update:modelValue', normalized)
|
||||
}
|
||||
|
||||
const extractDataArray = (data: unknown): ConstructeurSummary[] => {
|
||||
if (Array.isArray(data)) {
|
||||
return data as ConstructeurSummary[]
|
||||
}
|
||||
if (data && typeof data === 'object' && 'id' in data) {
|
||||
return [data as ConstructeurSummary]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
const ensureOptionsLoaded = async (force = false) => {
|
||||
if (!force && !searchTerm.value && constructeurs.value.length) {
|
||||
applyOptions(constructeurs.value as ConstructeurSummary[])
|
||||
@@ -262,7 +272,7 @@ const ensureOptionsLoaded = async (force = false) => {
|
||||
|
||||
const result = await searchConstructeurs(searchTerm.value)
|
||||
if (result.success) {
|
||||
applyOptions(result.data || [])
|
||||
applyOptions(extractDataArray(result.data))
|
||||
lastSearchTerm = searchTerm.value
|
||||
}
|
||||
}
|
||||
@@ -283,7 +293,7 @@ const onSearch = () => {
|
||||
}
|
||||
const result = await searchConstructeurs(searchTerm.value)
|
||||
if (result.success) {
|
||||
applyOptions(result.data || [])
|
||||
applyOptions(extractDataArray(result.data))
|
||||
lastSearchTerm = searchTerm.value
|
||||
}
|
||||
}, 250)
|
||||
@@ -310,16 +320,18 @@ const closeCreateModal = () => {
|
||||
|
||||
const handleCreate = async () => {
|
||||
creating.value = true
|
||||
const payload = { ...createForm.value }
|
||||
if (!payload.phone) {
|
||||
delete payload.phone
|
||||
const payload: { name: string; email?: string; phone?: string } = {
|
||||
name: createForm.value.name,
|
||||
}
|
||||
if (!payload.email) {
|
||||
delete payload.email
|
||||
if (createForm.value.email) {
|
||||
payload.email = createForm.value.email
|
||||
}
|
||||
if (createForm.value.phone) {
|
||||
payload.phone = createForm.value.phone
|
||||
}
|
||||
const result = await createConstructeur(payload)
|
||||
creating.value = false
|
||||
if (result.success) {
|
||||
if (result.success && result.data && !Array.isArray(result.data)) {
|
||||
emitSelection([...selectedIds.value, result.data.id])
|
||||
searchTerm.value = ''
|
||||
closeCreateModal()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="space-y-1">
|
||||
<SearchSelect
|
||||
:model-value="modelValue"
|
||||
:model-value="modelValue ?? undefined"
|
||||
:options="productOptions"
|
||||
:loading="loading"
|
||||
:placeholder="placeholder"
|
||||
|
||||
@@ -825,10 +825,9 @@ const customFieldReorderClass = (index: number) => {
|
||||
|
||||
const addCustomField = () => {
|
||||
ensureArray('customFields')
|
||||
const nextIndex = Array.isArray(props.node.customFields)
|
||||
? props.node.customFields.length
|
||||
: 0
|
||||
props.node.customFields.push({
|
||||
const fields = props.node.customFields!
|
||||
const nextIndex = fields.length
|
||||
fields.push({
|
||||
name: '',
|
||||
type: 'text',
|
||||
required: false,
|
||||
@@ -847,7 +846,7 @@ const removeCustomField = (index: number) => {
|
||||
|
||||
const addPiece = () => {
|
||||
ensureArray('pieces')
|
||||
props.node.pieces.push({
|
||||
props.node.pieces!.push({
|
||||
typePieceId: '',
|
||||
typePieceLabel: '',
|
||||
reference: '',
|
||||
@@ -863,7 +862,7 @@ const removePiece = (index: number) => {
|
||||
|
||||
const addProduct = () => {
|
||||
ensureArray('products')
|
||||
props.node.products.push({
|
||||
props.node.products!.push({
|
||||
typeProductId: '',
|
||||
typeProductLabel: '',
|
||||
familyCode: '',
|
||||
@@ -911,6 +910,7 @@ const moveItemInPlace = <T,>(list: T[], from: number, to: number) => {
|
||||
}
|
||||
const updated = list.slice()
|
||||
const [item] = updated.splice(from, 1)
|
||||
if (item === undefined) return
|
||||
updated.splice(to, 0, item)
|
||||
list.splice(0, list.length, ...updated)
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
type="text"
|
||||
class="input input-bordered input-sm"
|
||||
:placeholder="labels.labelPlaceholder"
|
||||
@input="updateRequirement(index, { label: $event.target.value })"
|
||||
@input="handleLabelInput(index, $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
type="number"
|
||||
min="0"
|
||||
class="input input-bordered input-sm"
|
||||
@input="updateRequirement(index, { minCount: parseNumber($event.target.value) })"
|
||||
@input="handleMinInput(index, $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
type="number"
|
||||
min="0"
|
||||
class="input input-bordered input-sm"
|
||||
@input="updateRequirement(index, { maxCount: parseOptionalNumber($event.target.value) })"
|
||||
@input="handleMaxInput(index, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,7 +113,7 @@
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
:checked="(requirement.required ?? requiredFallback) === true"
|
||||
@change="updateRequirement(index, { required: $event.target.checked })"
|
||||
@change="handleRequiredChange(index, $event)"
|
||||
/>
|
||||
{{ labels.requiredLabel }}
|
||||
</label>
|
||||
@@ -123,7 +123,7 @@
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-sm"
|
||||
:checked="(requirement.allowNewModels ?? allowNewModelsFallback) === true"
|
||||
@change="updateRequirement(index, { allowNewModels: $event.target.checked })"
|
||||
@change="handleAllowNewModelsChange(index, $event)"
|
||||
/>
|
||||
{{ labels.allowNewModelsLabel }}
|
||||
</label>
|
||||
@@ -277,6 +277,37 @@ const parseOptionalNumber = (value: string) => {
|
||||
return Number.isFinite(parsed) ? parsed : null
|
||||
}
|
||||
|
||||
// Type-safe event handlers
|
||||
const getInputValue = (event: Event): string => {
|
||||
const target = event.target as HTMLInputElement | null
|
||||
return target?.value ?? ''
|
||||
}
|
||||
|
||||
const getCheckboxValue = (event: Event): boolean => {
|
||||
const target = event.target as HTMLInputElement | null
|
||||
return target?.checked ?? false
|
||||
}
|
||||
|
||||
const handleLabelInput = (index: number, event: Event) => {
|
||||
updateRequirement(index, { label: getInputValue(event) })
|
||||
}
|
||||
|
||||
const handleMinInput = (index: number, event: Event) => {
|
||||
updateRequirement(index, { minCount: parseNumber(getInputValue(event)) })
|
||||
}
|
||||
|
||||
const handleMaxInput = (index: number, event: Event) => {
|
||||
updateRequirement(index, { maxCount: parseOptionalNumber(getInputValue(event)) })
|
||||
}
|
||||
|
||||
const handleRequiredChange = (index: number, event: Event) => {
|
||||
updateRequirement(index, { required: getCheckboxValue(event) })
|
||||
}
|
||||
|
||||
const handleAllowNewModelsChange = (index: number, event: Event) => {
|
||||
updateRequirement(index, { allowNewModels: getCheckboxValue(event) })
|
||||
}
|
||||
|
||||
const draggingRequirementIndex = ref<number | null>(null)
|
||||
const requirementDropTargetIndex = ref<number | null>(null)
|
||||
|
||||
@@ -297,6 +328,10 @@ const reorderRequirements = (from: number, to: number) => {
|
||||
}
|
||||
const updated = list.slice() as Requirement[]
|
||||
const [moved] = updated.splice(from, 1)
|
||||
if (!moved) {
|
||||
resetRequirementDragState()
|
||||
return
|
||||
}
|
||||
updated.splice(to, 0, moved)
|
||||
requirements.value = applyOrderIndex(updated)
|
||||
resetRequirementDragState()
|
||||
|
||||
Reference in New Issue
Block a user