diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue new file mode 100644 index 000000000..6b8c577a0 --- /dev/null +++ b/src/components/CrudModel.vue @@ -0,0 +1,339 @@ + + + + + { + "en": { + "confirmDeletion": "Confirm deletion", + "confirmDeletionMessage": "Are you sure you want to delete this?" + }, + "es": { + "confirmDeletion": "Confirmar eliminación", + "confirmDeletionMessage": "Seguro que quieres eliminar?" + } + } + diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index 2897997ed..3c05333f5 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -4,12 +4,14 @@ import { onMounted, onUnmounted, computed, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; import { useState } from 'src/composables/useState'; +import { useStateStore } from 'stores/useStateStore'; import { useValidator } from 'src/composables/useValidator'; import SkeletonForm from 'components/ui/SkeletonForm.vue'; const quasar = useQuasar(); -const { t } = useI18n(); const state = useState(); +const stateStore = useStateStore(); +const { t } = useI18n(); const { validate } = useValidator(); const $props = defineProps({ @@ -29,63 +31,41 @@ const $props = defineProps({ type: String, default: null, }, - crud: { - type: Boolean, - default: null, - }, - primaryKey: { - type: String, - default: 'id', - }, - dataRequired: { - type: Object, - default: null, - }, defaultActions: { type: Boolean, default: true, }, }); -const isLoading = ref(false); -const hasChanges = ref(false); -const formData = computed(() => state.get($props.model)); -const originalData = ref(); -const formUrl = computed(() => $props.url); -const stActionsExist = ref(false); - const emit = defineEmits(['onFetch']); defineExpose({ save, - insert, - remove, - onSubmit, - reset, - hasChanges, }); -onMounted(async () => { - await fetch(); - stActionsExist.value = !!document.querySelector('#st-actions'); -}); +onMounted(async () => await fetch()); onUnmounted(() => { state.unset($props.model); }); +const isLoading = ref(false); +const hasChanges = ref(false); +const originalData = ref(); +const formData = computed(() => state.get($props.model)); +const formUrl = computed(() => $props.url); + +function tMobile(...args) { + if (!quasar.platform.is.mobile) return t(...args); +} + async function fetch() { const { data } = await axios.get($props.url, { params: { filter: $props.filter }, }); - if (Array.isArray(data)) { - let $index = 0; - data.map((d) => (d.$index = $index++)); - } - state.set($props.model, data); - originalData.value = JSON.parse(JSON.stringify(data)); + originalData.value = Object.assign({}, data); watch(formData.value, () => (hasChanges.value = true)); @@ -100,29 +80,24 @@ async function save() { }); } isLoading.value = true; - try { - await axios.patch($props.urlUpdate || $props.url, formData.value); - } catch { - return (isLoading.value = false); - } + await axios.patch($props.urlUpdate || $props.url, formData.value); - originalData.value = JSON.parse(JSON.stringify(formData.value)); + originalData.value = formData.value; hasChanges.value = false; isLoading.value = false; } function reset() { state.set($props.model, originalData.value); - watch(formData.value, () => (hasChanges.value = true)); hasChanges.value = false; } // eslint-disable-next-line vue/no-dupe-keys function filter(value, update, filterOptions) { update( () => { - const { options, filterFn, field } = filterOptions; + const { options, filterFn } = filterOptions; - options.value = filterFn(options, value, field); + options.value = filterFn(options, value); }, (ref) => { ref.setOptionIndex(-1); @@ -131,167 +106,42 @@ function filter(value, update, filterOptions) { ); } -async function crudSave() { - if (!hasChanges.value) { - return quasar.notify({ - type: 'negative', - message: t('globals.noChanges'), - }); - } - isLoading.value = true; - await saveChanges(); -} - -async function saveChanges() { - const changes = getChanges(); - try { - await axios.post($props.urlUpdate || $props.url + '/crud', changes); - } catch (e) { - return (isLoading.value = false); - } - - originalData.value = JSON.parse(JSON.stringify(formData.value)); - hasChanges.value = false; - isLoading.value = false; - if (changes.creates?.length) await fetch(); -} - -async function insert() { - const $index = formData.value[formData.value.length - 1].$index + 1; - formData.value.push(Object.assign({ $index }, $props.dataRequired)); - hasChanges.value = true; -} - -// function addRemove(ids) { -// for (let id of ids) { -// const index = removed.value.indexOf(id); -// if (index > -1) { -// removed.value = removed.value.slice(index, 1); -// continue; -// } -// removed.value.push(id); -// } -// } - -async function remove(data) { - if (!data.length) - return quasar.notify({ - type: 'warning', - message: t('globals.noChanges'), - }); - - const pk = $props.primaryKey; - let ids = data.map((d) => d[pk]).filter(Boolean); - let preRemove = data.map((d) => d.$index).filter(Boolean); - let newData = formData.value; - - // addRemove(ids); - if (preRemove.length) { - newData = newData.filter( - (form) => !preRemove.some((index) => index == form.$index) - ); - state.set($props.model, newData); - const changes = getChanges(); - if (!changes.creates?.length && !changes.updates?.length) - hasChanges.value = false; - } - if (ids.length) { - await saveChanges({ deletes: ids }); - newData = newData.filter((form) => !ids.some((id) => id == form[pk])); - state.set($props.model, newData); - } -} - -async function onSubmit() { - if ($props.crud) return crudSave(); - return save(); -} - watch(formUrl, async () => { originalData.value = null; reset(); fetch(); }); - -function getChanges() { - const updates = []; - const creates = []; - - const pk = $props.primaryKey; - - for (const [i, row] of formData.value.entries()) { - if (!row[pk]) { - creates.push(row); - } else if (originalData.value) { - const data = getDifferences(originalData.value[i], row); - if (!isEmpty(data)) { - updates.push({ - data, - where: { [pk]: row[pk] }, - }); - } - } - } - const changes = { updates, creates }; - - for (let prop in changes) { - if (changes[prop].length === 0) changes[prop] = undefined; - } - - return changes; -} - -function getDifferences(obj1, obj2) { - let diff = {}; - for (let key in obj1) { - if (obj2[key] && obj1[key] !== obj2[key]) { - diff[key] = obj2[key]; - } - } - for (let key in obj2) { - if (obj1[key] === undefined && obj2[key]) { - diff[key] = obj2[key]; - } - } - return diff; -} - -function isEmpty(obj) { - if (obj == null) return true; - if (obj === undefined) return true; - if (Object.keys(obj).length === 0) return true; - - if (obj.length > 0) return false; -}