fix(documents): repair inline add-item modal on invoice/estimate create

Render a single shared ItemModal (was one per row, so stacked dialogs closed each other), validate the modal's own local form (vuelidate did not track the shared store object in the persistent modal), surface save errors, and carry the typed item name into the new-item form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Darko Gjorgjijoski
2026-06-14 23:42:12 +02:00
parent 9e496102d4
commit 3ca4027871
4 changed files with 134 additions and 83 deletions

View File

@@ -5,7 +5,6 @@ import { useUserStore } from '@/scripts/stores/user.store'
import { useModalStore } from '@/scripts/stores/modal.store'
import { useItemStore } from '@/scripts/features/company/items/store'
import { ABILITIES } from '@/scripts/config/abilities'
import ItemModal from '@/scripts/features/company/items/components/ItemModal.vue'
import type { Item } from '@/scripts/types/domain'
import type { Tax } from '@/scripts/types/domain'
@@ -58,6 +57,7 @@ const { t } = useI18n()
const itemSelect = ref<Item | null>(null)
const multiselectRef = ref<{ close?: () => void } | null>(null)
const loading = ref<boolean>(false)
const searchQuery = ref<string>('')
const itemData = reactive<LineItem>({ ...props.item })
async function searchItems(search: string): Promise<Item[]> {
@@ -65,6 +65,11 @@ async function searchItems(search: string): Promise<Item[]> {
return res.data as unknown as Item[]
}
function onSearchChange(val: string): void {
searchQuery.value = val
emit('search', val)
}
const description = computed<string | null>({
get: () => props.item.description,
set: (value: string | null) => {
@@ -81,10 +86,9 @@ function openItemModal(): void {
title: t('items.add_item'),
componentName: 'ItemModal',
refreshData: (val: Item) => emit('select', val),
// ItemModal owns its own form; hand it the typed search text to pre-fill the name.
data: {
taxPerItem: props.taxPerItem,
taxes: props.taxes,
itemIndex: props.index,
name: searchQuery.value,
},
})
})
@@ -100,8 +104,6 @@ function deselectItem(index: number): void {
<template>
<div class="flex-1 text-sm">
<ItemModal />
<!-- Selected Item Field -->
<div
v-if="item.item_id"
@@ -145,7 +147,7 @@ function deselectItem(index: number): void {
:options="searchItems"
object
@update:model-value="(val: Item) => $emit('select', val)"
@search-change="(val: string) => $emit('search', val)"
@search-change="onSearchChange"
>
<!-- Add Item Action -->
<template #action>