mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-07-18 14:55:21 +00:00
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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user