From 90b6f666d15a34c8dbe2ccbe36c56bc55252623c Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Fri, 27 Jan 2023 20:11:20 +0200 Subject: [PATCH] implement adding items to storage --- src/components/form/Form.vue | 28 ++ src/components/form/FormField.vue | 23 +- src/components/form/base/Autocomplete.vue | 2 + src/components/form/base/Select.vue | 1 + .../form/fields/FormAutocompleteField.vue | 6 +- src/components/form/fields/FormColorField.vue | 2 + src/components/form/fields/FormDateField.vue | 6 +- .../form/fields/FormSelectField.vue | 2 + .../form/fields/FormTextareaField.vue | 57 ++++ src/components/item/NewItemModal.vue | 296 ++++++++++++++++++ src/style.scss | 4 + src/views/Dashboard.vue | 2 + src/views/building/floors/FloorView.vue | 14 + 13 files changed, 436 insertions(+), 7 deletions(-) create mode 100644 src/components/form/fields/FormTextareaField.vue create mode 100644 src/components/item/NewItemModal.vue diff --git a/src/components/form/Form.vue b/src/components/form/Form.vue index da30468..a153327 100644 --- a/src/components/form/Form.vue +++ b/src/components/form/Form.vue @@ -28,6 +28,7 @@ const props = withDefaults( ); const isValid = ref(true); +const knownFields = ref([]); const invalidFields = ref([]); const formData = ref(props.modelValue); const formErrors = ref(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, }); diff --git a/src/components/form/FormField.vue b/src/components/form/FormField.vue index 7928759..1566194 100644 --- a/src/components/form/FormField.vue +++ b/src/components/form/FormField.vue @@ -6,7 +6,8 @@ 'block text-sm font-medium transition-colors duration-200', errors.length ? 'text-red-500' : 'text-gray-700', ]" - >{{ label }}{{ label }} + * 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>('formData'); const formErrors = inject>('formErrors'); const formGroup = inject>('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)); diff --git a/src/components/form/base/Autocomplete.vue b/src/components/form/base/Autocomplete.vue index 3f01189..8f4e8b2 100644 --- a/src/components/form/base/Autocomplete.vue +++ b/src/components/form/base/Autocomplete.vue @@ -8,6 +8,7 @@ :id="forId" :class="inputClass" :displayValue="(option: any) => getLabel(option)" + autocomplete="off" @change="query = $event.target.value" /> { 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', ]; diff --git a/src/components/form/base/Select.vue b/src/components/form/base/Select.vue index 7f0c102..f402817 100644 --- a/src/components/form/base/Select.vue +++ b/src/components/form/base/Select.vue @@ -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', ]; diff --git a/src/components/form/fields/FormAutocompleteField.vue b/src/components/form/fields/FormAutocompleteField.vue index b3da981..6a02698 100644 --- a/src/components/form/fields/FormAutocompleteField.vue +++ b/src/components/form/fields/FormAutocompleteField.vue @@ -4,10 +4,11 @@ :label="label" :placeholder="placeholder" :disabled="disabled" + :required="required" > -