implement adding items to storage
This commit is contained in:
parent
266e7194c0
commit
90b6f666d1
@ -28,6 +28,7 @@ const props = withDefaults(
|
||||
);
|
||||
|
||||
const isValid = ref(true);
|
||||
const knownFields = ref<string[]>([]);
|
||||
const invalidFields = ref<string[]>([]);
|
||||
const formData = ref<FormData>(props.modelValue);
|
||||
const formErrors = ref<FormErrors>(props.errors);
|
||||
@ -70,6 +71,7 @@ const validateField = async (field: string) => {
|
||||
const validateAll = async () => {
|
||||
const fields = props.validators
|
||||
.map((validator) => validator.field)
|
||||
.filter((field) => knownFields.value.includes(field))
|
||||
.filter((value, index, array) => array.indexOf(value) === index);
|
||||
if (!fields.length) return;
|
||||
return Promise.allSettled(fields.map((field) => validateField(field)));
|
||||
@ -80,6 +82,24 @@ const fieldChange = useDebounceFn(validateField, 300);
|
||||
provide('formData', formData);
|
||||
provide('formErrors', formErrors);
|
||||
provide('fieldChange', fieldChange);
|
||||
provide('registerField', (field: string) => {
|
||||
if (knownFields.value?.includes(field)) return;
|
||||
knownFields.value.push(field);
|
||||
});
|
||||
provide('unregisterField', (field: string) => {
|
||||
if (!knownFields.value?.includes(field)) return;
|
||||
knownFields.value = knownFields.value.filter((entry) => field !== entry);
|
||||
invalidFields.value = invalidFields.value.filter((entry) => field !== entry);
|
||||
if (formErrors.value[field]) {
|
||||
delete formErrors.value[field];
|
||||
}
|
||||
if (formData.value[field]) {
|
||||
delete formData.value[field];
|
||||
}
|
||||
if (!isValid.value) {
|
||||
isValid.value = !invalidFields.value.length;
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'submit', data: FormSubmit): void;
|
||||
@ -101,7 +121,15 @@ const onSubmit = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
formData.value = {};
|
||||
formErrors.value = {};
|
||||
invalidFields.value = [];
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
isValid,
|
||||
validateAll,
|
||||
reset,
|
||||
});
|
||||
</script>
|
||||
|
@ -6,7 +6,8 @@
|
||||
'block text-sm font-medium transition-colors duration-200',
|
||||
errors.length ? 'text-red-500' : 'text-gray-700',
|
||||
]"
|
||||
>{{ label }}</label
|
||||
>{{ label }}
|
||||
<span v-if="required" class="font-bold text-red-600">*</span></label
|
||||
>
|
||||
<slot
|
||||
name="input"
|
||||
@ -14,6 +15,7 @@
|
||||
:type="type"
|
||||
:id="forId"
|
||||
:fieldName="name"
|
||||
:fieldFQN="fieldName"
|
||||
:value="value"
|
||||
:placeholder="placeholder"
|
||||
:invalid="!!errors?.length"
|
||||
@ -32,6 +34,9 @@
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:step="step"
|
||||
:min="min"
|
||||
:max="max"
|
||||
@input="onInput"
|
||||
@change="onChange"
|
||||
@focus="onFocus"
|
||||
@ -51,7 +56,7 @@
|
||||
<script setup lang="ts">
|
||||
import set from 'lodash.set';
|
||||
import get from 'lodash.get';
|
||||
import { computed, ref, Ref } from 'vue';
|
||||
import { computed, onBeforeUnmount, onMounted, ref, Ref } from 'vue';
|
||||
import { inject } from 'vue';
|
||||
import { FormData, FormErrors, InputType } from './form.types';
|
||||
|
||||
@ -61,12 +66,17 @@ const props = withDefaults(
|
||||
forIdPrefix?: string;
|
||||
label: string;
|
||||
name: string;
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
placeholder?: string;
|
||||
step?: string;
|
||||
min?: string;
|
||||
max?: string;
|
||||
}>(),
|
||||
{
|
||||
type: 'text',
|
||||
required: false,
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
}
|
||||
@ -82,6 +92,8 @@ const formData = inject<Ref<FormData>>('formData');
|
||||
const formErrors = inject<Ref<FormErrors>>('formErrors');
|
||||
const formGroup = inject<Ref<string>>('formGroup', ref(''));
|
||||
const fieldChange = inject<(field: string) => void>('fieldChange');
|
||||
const registerField = inject<(field: string) => void>('registerField');
|
||||
const unregisterField = inject<(field: string) => void>('unregisterField');
|
||||
|
||||
const fieldName = computed(() =>
|
||||
formGroup?.value ? `${formGroup.value}.${props.name}` : props.name
|
||||
@ -127,7 +139,12 @@ const inputClass = computed(() => {
|
||||
errors.value.length
|
||||
? 'border-red-300 focus:border-red-500 focus:ring-red-500'
|
||||
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500',
|
||||
`mt-1 block w-full rounded-md shadow-sm sm:text-sm transition-colors duration-200`,
|
||||
props.type === 'checkbox' || props.type === 'radio' ? '' : 'w-full',
|
||||
props.disabled ? 'bg-gray-100 hover:border-gray-400' : '',
|
||||
`mt-1 block rounded-md shadow-sm sm:text-sm transition-colors duration-200`,
|
||||
];
|
||||
});
|
||||
|
||||
onMounted(() => registerField?.(fieldName.value));
|
||||
onBeforeUnmount(() => unregisterField?.(fieldName.value));
|
||||
</script>
|
||||
|
@ -8,6 +8,7 @@
|
||||
:id="forId"
|
||||
:class="inputClass"
|
||||
:displayValue="(option: any) => getLabel(option)"
|
||||
autocomplete="off"
|
||||
@change="query = $event.target.value"
|
||||
/>
|
||||
<ComboboxButton
|
||||
@ -130,6 +131,7 @@ const inputClass = computed(() => {
|
||||
props.invalid
|
||||
? 'border-red-300 focus:border-red-500 focus:ring-red-500'
|
||||
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500',
|
||||
props.disabled ? 'bg-gray-100 hover:border-gray-400' : '',
|
||||
`block w-full rounded-md shadow-sm sm:text-sm transition-colors duration-200`,
|
||||
'py-2 pl-3 pr-10 text-left cursor-default h-[38px] border-[1px] focus:ring-1',
|
||||
];
|
||||
|
@ -107,6 +107,7 @@ const inputClass = computed(() => {
|
||||
props.invalid
|
||||
? 'border-red-300 focus:border-red-500 focus:ring-red-500'
|
||||
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500',
|
||||
props.disabled ? 'bg-gray-100 hover:border-gray-400' : '',
|
||||
`block w-full rounded-md shadow-sm sm:text-sm transition-colors duration-200`,
|
||||
'py-2 pl-3 pr-10 text-left cursor-default h-[38px] border-[1px] focus:ring-1',
|
||||
];
|
||||
|
@ -4,10 +4,11 @@
|
||||
:label="label"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
>
|
||||
<template #input="{ invalid, forId, value, setValue }">
|
||||
<template #input="{ invalid, id, value, setValue }">
|
||||
<Autocomplete
|
||||
:for-id="forId"
|
||||
:for-id="id"
|
||||
:invalid="invalid"
|
||||
:disabled="disabled"
|
||||
:initialOptions="initialOptions"
|
||||
@ -44,6 +45,7 @@ const props = withDefaults(
|
||||
bindValue?: string;
|
||||
bindLabel?: string | ((obj: any) => string);
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
<FormField
|
||||
:name="name"
|
||||
:label="label"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
>
|
||||
@ -25,6 +26,7 @@ const props = withDefaults(
|
||||
forId?: string;
|
||||
label: string;
|
||||
name: string;
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
|
@ -3,14 +3,15 @@
|
||||
:name="name"
|
||||
:label="label"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
for-id-prefix="dp-input"
|
||||
>
|
||||
<template #input="{ invalid, fieldName, value, setValue }">
|
||||
<template #input="{ invalid, fieldFQN, value, setValue }">
|
||||
<Datepicker
|
||||
text-input
|
||||
arrow-navigation
|
||||
:class="[invalid ? 'dp__invalid' : '']"
|
||||
:uid="fieldName"
|
||||
:uid="fieldFQN"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:clearable="clearable"
|
||||
@ -32,6 +33,7 @@ interface DatePickerProps extends ExtractComponentProps<typeof Datepicker> {
|
||||
label: string;
|
||||
name: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
clearable?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
<FormField
|
||||
:name="name"
|
||||
:label="label"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
>
|
||||
@ -34,6 +35,7 @@ const props = withDefaults(
|
||||
label: string;
|
||||
name: string;
|
||||
options: SelectOption[];
|
||||
required?: boolean;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
}>(),
|
||||
|
57
src/components/form/fields/FormTextareaField.vue
Normal file
57
src/components/form/fields/FormTextareaField.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<FormField
|
||||
:name="name"
|
||||
:label="label"
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
:readonly="readonly"
|
||||
>
|
||||
<template #input="{ invalid, id, value, onInput, onFocus, onBlur }">
|
||||
<textarea
|
||||
:id="id"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:clearable="clearable"
|
||||
:model-value="(value as string)"
|
||||
:class="inputClass(invalid)"
|
||||
:rows="rows"
|
||||
:cols="cols"
|
||||
@input="onInput"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</template>
|
||||
<template #default><slot /></template>
|
||||
</FormField>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FormField from '../FormField.vue';
|
||||
|
||||
interface TextareaProps {
|
||||
label: string;
|
||||
name: string;
|
||||
rows?: string;
|
||||
cols?: string;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
clearable?: boolean;
|
||||
readonly?: boolean;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<TextareaProps>(), {
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
const inputClass = (invalid: boolean) => {
|
||||
return [
|
||||
invalid
|
||||
? 'border-red-300 focus:border-red-500 focus:ring-red-500'
|
||||
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500',
|
||||
props.disabled ? 'bg-gray-100 hover:border-gray-400' : '',
|
||||
`mt-1 block rounded-md shadow-sm sm:text-sm transition-colors duration-200`,
|
||||
];
|
||||
};
|
||||
</script>
|
296
src/components/item/NewItemModal.vue
Normal file
296
src/components/item/NewItemModal.vue
Normal file
@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<Modal ref="modalRef" size="xl">
|
||||
<template #title> Add a new item </template>
|
||||
|
||||
<template #default="{ closeModal }">
|
||||
<FormAlert :message="error" />
|
||||
<Form @submit="onSubmit" v-model="data" :validators="validators">
|
||||
<FormAutocompleteField
|
||||
v-if="typeof item !== 'string'"
|
||||
name="item"
|
||||
label="Item"
|
||||
required
|
||||
:search-fn="searchForItems"
|
||||
>
|
||||
<template #notfound="{ query }">
|
||||
<button @click="startAddingNewItem(query)">Add a new item</button>
|
||||
</template>
|
||||
</FormAutocompleteField>
|
||||
<template v-if="item && typeof item === 'string'">
|
||||
<FormField name="displayName" label="Display Name" required />
|
||||
<FormSelectField
|
||||
:options="itemTypesOptions"
|
||||
required
|
||||
name="type"
|
||||
label="Type"
|
||||
/>
|
||||
<FormField name="barcode" label="Barcode" />
|
||||
<FormField
|
||||
name="weight"
|
||||
type="number"
|
||||
step="0.001"
|
||||
label="Weight (g)"
|
||||
/>
|
||||
<FormField name="url" label="URL" />
|
||||
<FormField
|
||||
name="consumable"
|
||||
type="checkbox"
|
||||
label="Consumable / Food item"
|
||||
/>
|
||||
<FormField name="public" type="checkbox" label="Public item" />
|
||||
<FormTextareaField name="notes" label="Notes" />
|
||||
</template>
|
||||
|
||||
<FormGroup name="transactionInfo">
|
||||
<FormSelectField
|
||||
:options="itemTransactionTypesOptions"
|
||||
name="type"
|
||||
required
|
||||
label="Transaction type"
|
||||
:disabled="!item"
|
||||
/>
|
||||
<FormDateField
|
||||
name="actionAt"
|
||||
label="Action committed at"
|
||||
:disabled="!item"
|
||||
required
|
||||
/>
|
||||
|
||||
<div class="grid grid-cols-4 space-x-2">
|
||||
<FormField
|
||||
name="price"
|
||||
label="Cost"
|
||||
type="number"
|
||||
step=".01"
|
||||
class="col-span-3"
|
||||
:disabled="!item"
|
||||
/>
|
||||
<FormSelectField
|
||||
:options="currencies"
|
||||
:disabled="!item"
|
||||
name="currency"
|
||||
label="Currency"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormTextareaField
|
||||
:disabled="!item"
|
||||
name="notes"
|
||||
label="Additional notes about the transaction"
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup name="additionalInfo">
|
||||
<div class="grid grid-cols-3 space-x-2">
|
||||
<FormDateField
|
||||
name="expiresAt"
|
||||
label="Expires at"
|
||||
:disabled="!item"
|
||||
/>
|
||||
<FormDateField
|
||||
name="acquiredAt"
|
||||
label="Acquired at"
|
||||
:disabled="!item"
|
||||
/>
|
||||
<FormDateField
|
||||
name="consumedAt"
|
||||
label="Consumed at"
|
||||
:disabled="!item"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormTextareaField
|
||||
name="notes"
|
||||
label="Additional notes about the individual stored item"
|
||||
:disabled="!item"
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</Form>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useAccessToken } from '../../composables/useAccessToken';
|
||||
import { BACKEND_URL } from '../../constants';
|
||||
import { BuildingListItem } from '../../interfaces/building.interfaces';
|
||||
import {
|
||||
StorageItem,
|
||||
StorageListItem,
|
||||
StoredItem,
|
||||
} from '../../interfaces/storage.interfaces';
|
||||
import jfetch from '../../utils/jfetch';
|
||||
import takeError from '../../utils/take-error';
|
||||
import { FormSubmit, SelectOption } from '../form/form.types';
|
||||
import Form from '../form/Form.vue';
|
||||
import FormAlert from '../form/FormAlert.vue';
|
||||
import FormField from '../form/FormField.vue';
|
||||
import FormSelectField from '../form/fields/FormSelectField.vue';
|
||||
import { IsRequired, MinLength } from '../form/validators';
|
||||
import Modal from '../Modal.vue';
|
||||
import { ItemType, ItemTypeName } from '../../enums/item-type.enum';
|
||||
import {
|
||||
TransactionType,
|
||||
TransactionTypeDescription,
|
||||
TransactionTypeName,
|
||||
} from '../../enums/transaction-type.enum';
|
||||
import FormGroup from '../form/FormGroup.vue';
|
||||
import FormDateField from '../form/fields/FormDateField.vue';
|
||||
import FormAutocompleteField from '../form/fields/FormAutocompleteField.vue';
|
||||
import { FormValidator } from '../form/validator.types';
|
||||
import deepUnref from '../../utils/deep-unref';
|
||||
import FormTextareaField from '../form/fields/FormTextareaField.vue';
|
||||
|
||||
const defaults: any = {
|
||||
item: null,
|
||||
transactionInfo: {
|
||||
actionAt: new Date(),
|
||||
},
|
||||
additionalInfo: {
|
||||
acquiredAt: new Date(),
|
||||
},
|
||||
};
|
||||
|
||||
const { authHeader } = useAccessToken();
|
||||
const modalRef = ref<InstanceType<typeof Modal>>();
|
||||
const building = ref<BuildingListItem>();
|
||||
const storage = ref<StorageListItem>();
|
||||
const item = ref<StorageItem | string | null>(null);
|
||||
const data: any = ref({
|
||||
...deepUnref(defaults),
|
||||
});
|
||||
const error = ref('');
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'added', storage: StoredItem): void;
|
||||
}>();
|
||||
|
||||
const itemTypesOptions = computed(() => {
|
||||
return Object.keys(ItemTypeName).reduce<SelectOption[]>(
|
||||
(list, key) => [
|
||||
...list,
|
||||
{
|
||||
value: key.toString(),
|
||||
name: ItemTypeName[key as ItemType],
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
const itemTransactionTypesOptions = computed(() => {
|
||||
return Object.keys(TransactionTypeName).reduce<SelectOption[]>(
|
||||
(list, key) => [
|
||||
...list,
|
||||
{
|
||||
value: key.toString(),
|
||||
name: TransactionTypeName[key as TransactionType],
|
||||
description: TransactionTypeDescription[key as TransactionType],
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
const validators = ref<FormValidator[]>([
|
||||
{
|
||||
field: 'displayName',
|
||||
validators: [MinLength(3), IsRequired()],
|
||||
},
|
||||
{
|
||||
field: 'type',
|
||||
validators: [IsRequired()],
|
||||
},
|
||||
{
|
||||
field: 'transactionInfo.type',
|
||||
validators: [IsRequired()],
|
||||
},
|
||||
{
|
||||
field: 'transactionInfo.actionAt',
|
||||
validators: [IsRequired()],
|
||||
},
|
||||
]);
|
||||
|
||||
const currencies = [
|
||||
{
|
||||
value: 'EUR',
|
||||
name: 'EUR',
|
||||
},
|
||||
{
|
||||
value: 'USD',
|
||||
name: 'USD',
|
||||
},
|
||||
];
|
||||
|
||||
const searchForItems = async (search: string) => {
|
||||
if (!search || search.length < 3) return [];
|
||||
const { data: list } = await jfetch(
|
||||
`${BACKEND_URL}/storage/item?searchTerm=${search}`,
|
||||
{
|
||||
headers: authHeader.value,
|
||||
}
|
||||
);
|
||||
return list;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openModal: (useBuilding: BuildingListItem, useStorage: StorageListItem) => {
|
||||
building.value = useBuilding;
|
||||
storage.value = useStorage;
|
||||
item.value = null;
|
||||
data.value = {
|
||||
...deepUnref(defaults),
|
||||
};
|
||||
modalRef.value?.openModal();
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => data.value.item,
|
||||
(selected) => {
|
||||
if (selected && selected.id) {
|
||||
item.value = selected;
|
||||
return;
|
||||
}
|
||||
item.value = null;
|
||||
}
|
||||
);
|
||||
|
||||
const startAddingNewItem = (insert: string) => {
|
||||
item.value = insert;
|
||||
data.value['displayName'] = insert;
|
||||
};
|
||||
|
||||
const onSubmit = async (form: FormSubmit) => {
|
||||
error.value = '';
|
||||
if (!form.isValid || !storage.value) return;
|
||||
|
||||
const body = {
|
||||
...form.formData,
|
||||
};
|
||||
delete body.item;
|
||||
|
||||
const requestUrl = `${BACKEND_URL}/storage/item/${storage.value.id}${
|
||||
item.value && typeof item.value !== 'string' ? `/${item.value.id}` : ''
|
||||
}`;
|
||||
|
||||
let createdStoredItem: StoredItem;
|
||||
try {
|
||||
const { data: response } = await jfetch(requestUrl, {
|
||||
method: 'POST',
|
||||
headers: authHeader.value,
|
||||
body,
|
||||
});
|
||||
createdStoredItem = response;
|
||||
} catch (e) {
|
||||
error.value = takeError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
emit('added', createdStoredItem);
|
||||
modalRef.value?.closeModal();
|
||||
};
|
||||
</script>
|
@ -6,6 +6,10 @@
|
||||
.dp__input {
|
||||
@apply block w-full rounded-md border-gray-300 shadow-sm transition-colors duration-200 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 sm:text-sm;
|
||||
height: 38px;
|
||||
|
||||
&.dp__disabled {
|
||||
@apply bg-gray-100 hover:border-gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
.dp__invalid .dp__input {
|
||||
|
@ -17,6 +17,7 @@
|
||||
name="autocomplete"
|
||||
label="autocomplete"
|
||||
/>
|
||||
<FormTextareaField name="textarea" label="textarea" rows="3" />
|
||||
<button type="submit">test</button>
|
||||
</Form>
|
||||
</StandardLayout>
|
||||
@ -31,6 +32,7 @@ import Form from '../components/form/Form.vue';
|
||||
import FormField from '../components/form/FormField.vue';
|
||||
import { IsRequired } from '../components/form/validators';
|
||||
import FormAutocompleteField from '../components/form/fields/FormAutocompleteField.vue';
|
||||
import FormTextareaField from '../components/form/fields/FormTextareaField.vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const user = ref(userStore.user);
|
||||
|
@ -118,6 +118,7 @@
|
||||
@select-room="selectRoomFromList"
|
||||
@select-storage="selectStorage"
|
||||
@new-storage="addNewStorage"
|
||||
@add-item="newItem?.openModal(building!, selectedStorage!)"
|
||||
/>
|
||||
|
||||
<StoredItemCard
|
||||
@ -127,6 +128,7 @@
|
||||
/>
|
||||
|
||||
<NewStorageModal ref="newStorage" @added="storageAdded" />
|
||||
<NewItemModal ref="newItem" @added="newStoredItemAdded" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -150,6 +152,7 @@ import {
|
||||
StorageListItem,
|
||||
StorageSetListItem,
|
||||
StorageSharedType,
|
||||
StoredItem,
|
||||
} from '../../../interfaces/storage.interfaces';
|
||||
import StorageBubble from './StorageBubble.vue';
|
||||
import RoomPolygon from './RoomPolygon.vue';
|
||||
@ -158,6 +161,7 @@ import isSet from '../../../utils/is-storage-set';
|
||||
import ItemSelector from './ItemSelector.vue';
|
||||
import StoredItemCard from '../../../components/item/StoredItemCard.vue';
|
||||
import NewStorageModal from '../../../components/item/NewStorageModal.vue';
|
||||
import NewItemModal from '../../../components/item/NewItemModal.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const buildingStore = useBuildingStore();
|
||||
@ -174,6 +178,7 @@ const selectedSet = ref<StorageSetListItem>();
|
||||
const selectedStorage = ref<StorageListItem>();
|
||||
|
||||
const newStorage = ref<InstanceType<typeof NewStorageModal>>();
|
||||
const newItem = ref<InstanceType<typeof NewItemModal>>();
|
||||
|
||||
const floor = computed(() =>
|
||||
building.value?.floors.find(
|
||||
@ -319,4 +324,13 @@ const storageAdded = async (newStorage: StorageSharedType) => {
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const newStoredItemAdded = async (newItem: StoredItem) => {
|
||||
if (!selectedStorage.value) return;
|
||||
selectedStorage.value.items = [
|
||||
newItem,
|
||||
...(selectedStorage.value.items || []),
|
||||
];
|
||||
selectedStorage.value.itemCount = selectedStorage.value.items.length;
|
||||
};
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user