Parcourir la source

feat: :sparkles: crud client favorite providers

crud client favorite providers
Gustavo Zanatta il y a 1 mois
Parent
commit
317dc53270

+ 31 - 0
src/api/clientFavoriteProvider.js

@@ -0,0 +1,31 @@
+import api from "src/api";
+
+export const getClientFavoriteProviders = async (clientId) => {
+  const { data } = await api.get(`/client/favorite-providers/${clientId}`);
+  return data.payload;
+}
+
+export const getClientFavoriteProvider = async (id) => {
+  const { data } = await api.get(`/client/favorite-provider/${id}`);
+  return data.payload;
+}
+
+export const getFavoritedProviderIds = async (clientId) => {
+  const { data } = await api.get(`/client/favorited-providers/${clientId}`);
+  return data.payload;
+}
+
+export const createClientFavoriteProvider = async (info) => {
+  const { data } = await api.post(`/client/favorite-provider`, info);
+  return data.payload;
+}
+
+export const updateClientFavoriteProvider = async (id, info) => {
+  const { data } = await api.put(`/client/favorite-provider/${id}`, info);
+  return data.payload;
+}
+
+export const deleteClientFavoriteProvider = async (id) => {
+  const { data } = await api.delete(`/client/favorite-provider/${id}`);
+  return data.payload;
+}

+ 13 - 7
src/components/provider/ProviderSelect.vue

@@ -31,7 +31,7 @@ import { ref, onMounted } from "vue";
 import { normalizeString } from "src/helpers/utils";
 import { useI18n } from "vue-i18n";
 
-const { label, rules, initialId } = defineProps({
+const { label, rules, initialId, excludeIds } = defineProps({
   label: {
     type: String,
     default: () => useI18n().t("ui.navigation.provider"),
@@ -45,6 +45,10 @@ const { label, rules, initialId } = defineProps({
     required: false,
     default: null,
   },
+  excludeIds: {
+    type: Array,
+    default: () => [],
+  },
   error: {
     type: Boolean,
     default: false,
@@ -90,12 +94,14 @@ onMounted(async () => {
   try {
     loading.value = true;
     const baseProviders = await getProviders();
-    baseOptions.value = baseProviders.map((provider) => ({
-      label: provider.user?.name || provider.document,
-      value: provider.id,
-      document: provider.document,
-      user_id: provider.user_id,
-    }));
+    baseOptions.value = baseProviders
+      .filter(provider => !excludeIds.includes(provider.id))
+      .map((provider) => ({
+        label: provider.user?.name || provider.document,
+        value: provider.id,
+        document: provider.document,
+        user_id: provider.user_id,
+      }));
     providerOptions.value = baseOptions.value;
     if (initialId) {
       selectProviderById(initialId);

+ 11 - 0
src/i18n/locales/en.json

@@ -385,6 +385,17 @@
       "all": "All Day"
     }
   },
+  "client_favorite_providers": {
+    "singular": "Favorite Provider",
+    "plural": "Favorite Providers",
+    "header": "Favorite Providers",
+    "add_button": "Add Favorite Provider",
+    "edit_button": "Edit Favorite Provider",
+    "empty_state": "No favorite providers registered",
+    "provider": "Provider",
+    "notes": "Notes",
+    "favorited_at": "Favorited at"
+  },
   "orders": {
     "singular": "Order",
     "plural": "Orders",

+ 11 - 0
src/i18n/locales/es.json

@@ -385,6 +385,17 @@
       "all": "Día Completo"
     }
   },
+  "client_favorite_providers": {
+    "singular": "Proveedor Favorito",
+    "plural": "Proveedores Favoritos",
+    "header": "Proveedores Favoritos",
+    "add_button": "Agregar Proveedor Favorito",
+    "edit_button": "Editar Proveedor Favorito",
+    "empty_state": "No hay proveedores favoritos registrados",
+    "provider": "Proveedor",
+    "notes": "Observaciones",
+    "favorited_at": "Favoritado en"
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

+ 11 - 0
src/i18n/locales/pt.json

@@ -385,6 +385,17 @@
       "all": "Dia Todo"
     }
   },
+  "client_favorite_providers": {
+    "singular": "Prestador Favorito",
+    "plural": "Prestadores Favoritos",
+    "header": "Prestadores Favoritos",
+    "add_button": "Adicionar Prestador Favorito",
+    "edit_button": "Editar Prestador Favorito",
+    "empty_state": "Nenhum prestador favorito cadastrado",
+    "provider": "Prestador",
+    "notes": "Observações",
+    "favorited_at": "Favoritado em"
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

+ 10 - 5
src/pages/client/components/AddEditClientDialog.vue

@@ -13,6 +13,7 @@
       >
         <q-tab name="data" label="Dados" />
         <q-tab v-if="client" name="addresses" :label="$t('address.tab')" />
+        <q-tab v-if="client" name="favorites" :label="$t('client_favorite_providers.header')" />
       </q-tabs>
 
       <q-separator v-if="client" />
@@ -65,6 +66,10 @@
             :source-id="client.id"
           />
         </q-tab-panel>
+
+        <q-tab-panel v-if="client" name="favorites">
+          <ClientFavoriteProvidersPanel :client-id="client.id" />
+        </q-tab-panel>
       </q-tab-panels>
     </q-card>
   </q-dialog>
@@ -83,6 +88,7 @@ import { dynamicCpfCnpjMask, validateCpfCnpj } from 'src/helpers/utils';
 import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue';
 import UserSelect from 'src/components/user/UserSelect.vue';
 import AddressesPanel from 'src/pages/address/components/AddressesPanel.vue';
+import ClientFavoriteProvidersPanel from './ClientFavoriteProvidersPanel.vue';
 
 defineEmits([
   ...useDialogPluginComponent.emits,
@@ -124,19 +130,17 @@ const {
 
 const selectedUser = ref(null);
 
-// Dynamic mask for CPF/CNPJ
 const documentMask = computed(() => {
   return dynamicCpfCnpjMask(form.document);
 });
 
-// CPF/CNPJ validation
 const validateDocument = (val) => {
   if (!val) return true;
   return validateCpfCnpj(val) || t('validation.rules.cpf') + ' / ' + t('validation.rules.cnpj');
 };
 
 const onOKClick = async () => {
-    let response;
+  let response;
   if (client) {
     await submitForm(() => {
       response = updateClient(getUpdatedFields.value, client.id);
@@ -146,8 +150,9 @@ const onOKClick = async () => {
       response = createClient({ ...form });
     });
   }
-  response;
-//   if(response.data.success == false)
+  if(response.data.success == true) {
+    onDialogOK(true);
+  }
 };
 
 watch(selectedUser, () => {

+ 128 - 0
src/pages/client/components/AddEditClientFavoriteProviderDialog.vue

@@ -0,0 +1,128 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="q-dialog-plugin" style="width: 700px; max-width: 90vw">
+      <DefaultDialogHeader :title="title" @close="onDialogCancel" />
+      <q-form ref="formRef" @submit="onOKClick">
+        <q-card-section class="row q-col-gutter-sm">
+          <ProviderSelect
+            v-model="selectedProvider"
+            :label="$t('client_favorite_providers.provider')"
+            :rules="[inputRules.required]"
+            :error="!!serverErrors?.provider_id"
+            :error-message="serverErrors?.provider_id"
+            :initial-id="favorite ? favorite.provider_id : null"
+            :exclude-ids="excludedProviderIds"
+            class="col-12"
+            @update:model-value="serverErrors.provider_id = null"
+          />
+
+          <q-input
+            v-model="form.notes"
+            :label="$t('client_favorite_providers.notes')"
+            :error="!!serverErrors?.notes"
+            :error-message="serverErrors?.notes"
+            type="textarea"
+            rows="4"
+            class="col-12"
+            @update:model-value="serverErrors.notes = null"
+          />
+        </q-card-section>
+
+        <q-card-actions align="right">
+          <q-btn
+            flat
+            :label="$t('common.actions.cancel')"
+            color="negative"
+            @click="onDialogCancel"
+          />
+          <q-btn
+            type="submit"
+            :label="$t('common.actions.save')"
+            :loading="loading"
+            :disable="!hasUpdatedFields"
+            color="primary"
+          />
+        </q-card-actions>
+      </q-form>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useDialogPluginComponent } from 'quasar'
+import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker'
+import { useSubmitHandler } from 'src/composables/useSubmitHandler'
+import {
+  createClientFavoriteProvider,
+  updateClientFavoriteProvider,
+  getFavoritedProviderIds
+} from 'src/api/clientFavoriteProvider'
+import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue'
+import ProviderSelect from 'src/components/provider/ProviderSelect.vue'
+import { useInputRules } from 'src/composables/useInputRules'
+
+const props = defineProps({
+  favorite: {
+    type: Object,
+    default: null
+  },
+  clientId: {
+    type: Number,
+    required: true
+  },
+  title: {
+    type: Function,
+    default: () => ''
+  }
+})
+
+defineEmits([...useDialogPluginComponent.emits])
+const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
+const { inputRules } = useInputRules()
+const formRef = ref(null)
+const selectedProvider = ref(null)
+const excludedProviderIds = ref([])
+
+const { form, getUpdatedFields, hasUpdatedFields } = useFormUpdateTracker({
+  client_id: props.favorite ? props.favorite.client_id : props.clientId,
+  provider_id: props.favorite ? props.favorite.provider_id : null,
+  notes: props.favorite ? props.favorite.notes : null
+})
+
+const {
+  loading,
+  serverErrors,
+  execute: submitForm,
+} = useSubmitHandler({
+  onSuccess: () => onDialogOK(true),
+  formRef: formRef,
+})
+
+const onOKClick = async () => {
+  if (selectedProvider.value?.value) {
+    form.provider_id = selectedProvider.value.value
+  }
+
+  if (props.favorite) {
+    await submitForm(() => updateClientFavoriteProvider(props.favorite.id, getUpdatedFields.value))
+  } else {
+    await submitForm(() => createClientFavoriteProvider({ ...form }))
+  }
+};
+
+onMounted(async () => {
+  try {
+    const favoritedIds = await getFavoritedProviderIds(props.clientId)
+    excludedProviderIds.value = props.favorite
+      ? favoritedIds.filter(id => id !== props.favorite.provider_id)
+      : favoritedIds
+  } catch (error) {
+    console.error('Error loading favorited providers:', error)
+  }
+
+  if (props.clientId) {
+    form.client_id = props.clientId
+  }
+})
+</script>

+ 104 - 0
src/pages/client/components/ClientFavoriteProvidersPanel.vue

@@ -0,0 +1,104 @@
+<template>
+  <DefaultTable
+    ref="tableRef"
+    :columns="columns"
+    :loading="loading"
+    :api-call="() => getClientFavoriteProviders(props.clientId)"
+    :add-button-label="$t('client_favorite_providers.add_button')"
+    :empty-message="$t('client_favorite_providers.empty_state')"
+    :delete-function="deleteClientFavoriteProvider"
+    :mostrar-selecao-de-colunas="false"
+    :mostrar-botao-fullscreen="false"
+    :mostrar-toggle-inativos="false"
+    @on-row-click="onRowClick"
+    @on-add-item="onAddItem"
+  >
+    <template #body-cell-favorited_at="template_props">
+      <q-td :props="template_props">
+        {{ format(parseISO(template_props.row.created_at)) }}
+      </q-td>
+    </template>
+  </DefaultTable>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { useQuasar } from 'quasar'
+import { getClientFavoriteProviders, deleteClientFavoriteProvider } from 'src/api/clientFavoriteProvider'
+import DefaultTable from 'src/components/defaults/DefaultTable.vue'
+import AddEditClientFavoriteProviderDialog from './AddEditClientFavoriteProviderDialog.vue'
+import { format, parseISO } from 'date-fns'
+
+const props = defineProps({
+  clientId: {
+    type: Number,
+    required: true
+  }
+})
+
+const { t } = useI18n()
+const $q = useQuasar()
+const tableRef = ref(null)
+const loading = ref(false)
+
+const columns = computed(() => [
+  {
+    name: 'provider_name',
+    label: t('client_favorite_providers.provider'),
+    align: 'left',
+    field: 'provider_name',
+    sortable: true
+  },
+  {
+    name: 'notes',
+    label: t('client_favorite_providers.notes'),
+    align: 'left',
+    field: 'notes',
+    sortable: false
+  },
+  {
+    name: 'favorited_at',
+    label: t('client_favorite_providers.favorited_at'),
+    align: 'left',
+    field: 'created_at',
+    sortable: true
+  },
+  {
+    name: 'actions',
+    label: t('common.terms.actions'),
+    align: 'center',
+    field: 'actions'
+  }
+])
+
+const onAddItem = () => {
+  $q.dialog({
+    component: AddEditClientFavoriteProviderDialog,
+    componentProps: {
+      clientId: props.clientId,
+      title: () => t('client_favorite_providers.add_button')
+    }
+  }).onOk((success) => {
+    if(success) {
+      tableRef.value.refresh()
+    }
+  })
+}
+
+const onRowClick = (favorite) => {
+  $q.dialog({
+    component: AddEditClientFavoriteProviderDialog,
+    componentProps: {
+      favorite,
+      clientId: props.clientId,
+      title: () => t('client_favorite_providers.edit_button')
+    }
+  }).onOk((success) => {
+    if(success) {
+      tableRef.value.refresh()
+    }
+  })
+}
+
+</script>