Parcourir la source

ajustes gerais antes da apresentacao

Gustavo Zanatta il y a 3 semaines
Parent
commit
90046190aa

+ 6 - 1
src/api/partnerAgreement.js

@@ -1,7 +1,7 @@
 import api from "src/api";
 
 export const getPartnerAgreements = async () => {
-  const { data } = await api.get("/partner-agreement");
+  const { data } = await api.get("/associado-partner-agreement");
   return data.payload;
 };
 
@@ -14,6 +14,11 @@ export const getPartnerAgreementsPaginated = async ({ page = 1, perPage = 10, fi
   return { data: { result: data.payload } };
 };
 
+export const getExpiringPartnerAgreementsPaginated = async ({ page = 1, perPage = 10, days = 30 } = {}) => {
+  const { data } = await api.get("/partner-agreement/expiring", { params: { page, per_page: perPage, days } });
+  return { data: { result: data.payload } };
+};
+
 export const getPartnerAgreement = async (id) => {
   const { data } = await api.get(`/partner-agreement/${id}`);
   return data.payload;

+ 5 - 1
src/api/relatorio.js

@@ -26,7 +26,7 @@ export const getExclusoesMesPaginated = async ({ page = 1, perPage = 10, filter
   return { data: { result: data.payload } };
 };
 
-export const exportRelatorio = async (tipo) => {
+export const exportRelatorio = async (tipo, search) => {
   const nomes = {
     "novos-associados": "novos_associados",
     "contatos-associados": "contatos_associados",
@@ -39,8 +39,12 @@ export const exportRelatorio = async (tipo) => {
   const yyyy = hoje.getFullYear();
   const filename = `${nomes[tipo]}_${dd}-${mm}-${yyyy}.xlsx`;
 
+  const params = {};
+  if (search) params.search = search;
+
   const response = await api.get(`/relatorio/${tipo}/export`, {
     responseType: "blob",
+    params,
   });
 
   const url = window.URL.createObjectURL(new Blob([response.data]));

+ 1 - 0
src/components/defaults/DefaultSelect.vue

@@ -14,6 +14,7 @@
       :error-message="errorMessage"
       :rules
       hide-bottom-space
+      class="input-violet"
       :class="inputClass"
       :popup-content-class="popupContentClass"
       @update:model-value="error = null"

+ 1 - 0
src/components/defaults/DefaultTableServerSide.vue

@@ -362,6 +362,7 @@ const usableSlots = (slots) => {
 
 defineExpose({
   refresh: onRequest,
+  getFilter: () => pagination.value.filter,
 });
 </script>
 

+ 1 - 0
src/helpers/utils.js

@@ -68,6 +68,7 @@ const convertDateTime = (dateTimeString) => {
  * // Output: 23/05/2023 10:07:27
  */
 const formatDateYMDtoDMY = (dateTime) => {
+  if (!dateTime) return "—";
   const [datePart, timePart] = dateTime.split(" ");
   const [year, month, day] = datePart.split("-");
   const formattedDate = `${day}/${month}/${year}`;

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

@@ -623,6 +623,7 @@
     "tab_horario": "Schedule & Contract",
     "tab_servicos": "My Services",
     "usuario_parceiro": "Partner User",
+    "home": "Partner Portal",
     "parceiro": {
       "dashboard": {
         "title": "Partner Portal",

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

@@ -592,6 +592,7 @@
     "category": "Categoría",
     "company_name": "Nombre de la Empresa",
     "responsible": "Responsable",
+    "linked_user": "Usuario Vinculado",
     "discount_percentage": "Descuento (%)",
     "logo": "Logo",
     "website": "Sitio Web",
@@ -622,6 +623,7 @@
     "tab_horario": "Horario y Contrato",
     "tab_servicos": "Mis Servicios",
     "usuario_parceiro": "Usuario Socio",
+    "home": "Portal del Socio",
     "parceiro": {
       "dashboard": {
         " title": "Portal del Socio",

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

@@ -593,6 +593,7 @@
     "category": "Categoria",
     "company_name": "Nome da Empresa",
     "responsible": "Responsável",
+    "linked_user": "Usuário Vinculado",
     "discount_percentage": "Desconto (%)",
     "logo": "Logo",
     "website": "Website",
@@ -623,6 +624,7 @@
     "tab_horario": "Horário e Contrato",
     "tab_servicos": "Meus Serviços",
     "usuario_parceiro": "Usuário Parceiro",
+    "home": "Portal do Parceiro",
     "dashboard": {
       "title": "Portal do Parceiro",
       "authorization": "Consultas para Autorização",

+ 7 - 4
src/pages/dashboard/DashboardPage.vue

@@ -65,7 +65,7 @@ import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
 import DefaultTableServerSide from "src/components/defaults/DefaultTableServerSide.vue";
 import { getDashboardStats } from "src/api/dashboard";
 import { getUsersPaginated } from "src/api/user";
-import { getPartnerAgreementsPaginated } from "src/api/partnerAgreement";
+import { getPartnerAgreementsPaginated, getExpiringPartnerAgreementsPaginated } from "src/api/partnerAgreement";
 import { formatDateYMDtoDMY, getStatusColor, getStatusI18nKey } from "src/helpers/utils";
 
 const { t } = useI18n();
@@ -124,7 +124,7 @@ const activeApiCall = computed(() => {
     case "parceiros":
       return (p) => getPartnerAgreementsPaginated({ ...p });
     case "contratos_a_vencer":
-      return (p) => getPartnerAgreementsPaginated({ ...p, expiresInDays: 30 });
+      return (p) => getExpiringPartnerAgreementsPaginated({ ...p });
     case "novos_mes":
       return (p) => getPartnerAgreementsPaginated({ ...p, createdMonth: "current" });
     default:
@@ -148,7 +148,8 @@ onMounted(async () => {
 <style scoped>
 .stat-card {
   border-radius: 12px;
-  transition: box-shadow 0.2s;
+  border: 2px solid transparent;
+  transition: box-shadow 0.2s, border-color 0.2s, background-color 0.2s;
 }
 
 .stat-card:hover {
@@ -156,6 +157,8 @@ onMounted(async () => {
 }
 
 .stat-card--active {
-  box-shadow: 0 0 0 2px var(--q-violet-normal);
+  border-color: #4d1658;
+  background-color: #f0e8f1 !important;
+  box-shadow: 0 2px 12px rgba(77, 22, 88, 0.18);
 }
 </style>

+ 2 - 1
src/pages/loja/LojaPage.vue

@@ -86,12 +86,14 @@
                     </div>
                     <div class="row no-wrap items-center" style="gap: 2px">
                       <q-btn
+                        v-if="isActive(item)"
                         flat round dense size="sm"
                         color="negative"
                         icon="mdi-pause-circle-outline"
                         @click="onSetStatus(item, 'inactive')"
                       />
                       <q-btn
+                        v-else
                         flat round dense size="sm"
                         color="positive"
                         icon="mdi-play-circle-outline"
@@ -311,7 +313,6 @@ const onSetStatus = async (item) => {
     const updated = await toggleStoreItemStatus(item.id);
     const idx = items.value.findIndex((i) => i.id === item.id);
     if (idx !== -1) items.value[idx] = { ...items.value[idx], ...updated };
-    $q.notify({ type: "positive", message: t("http.success") });
   } catch {
     $q.notify({ type: "negative", message: t("http.errors.failed") });
   }

+ 42 - 18
src/pages/parceiros-convenios/ParceiroCadastroPage.vue

@@ -53,11 +53,40 @@
                 v-model:error="errorsDados.category_id"
                 class="col-12"
               />
-              <ParceiroSelect
-                v-model="selectedUser"
-                v-model:error="errorsDados.user_id"
-                class="col-12 input-violet"
+
+              <!-- Novo usuário — apenas na criação -->
+              <template v-if="!partnerId">
+                <DefaultInput
+                  v-model="newUser.name"
+                  :rules="[inputRules.required]"
+                  :label="$t('common.terms.name')"
+                  class="col-12"
+                />
+                <DefaultInput
+                  v-model="newUser.email"
+                  :rules="[inputRules.required, inputRules.email]"
+                  :label="$t('common.terms.email')"
+                  type="email"
+                  class="col-12"
+                />
+                <DefaultInput
+                  v-model="newUser.password"
+                  :rules="[inputRules.required]"
+                  :label="$t('common.terms.password')"
+                  type="password"
+                  class="col-12"
+                />
+              </template>
+
+              <!-- Usuário vinculado — apenas na edição -->
+              <DefaultInput
+                v-else-if="partner?.user"
+                :model-value="partner.user.name"
+                :label="$t('parceiro.linked_user')"
+                disable
+                class="col-12"
               />
+
               <DefaultInput
                 v-model="formDados.responsible"
                 v-model:error="errorsDados.responsible"
@@ -332,7 +361,7 @@
 </template>
 
 <script setup>
-import { ref, computed, watch, onMounted, nextTick, useTemplateRef } from "vue";
+import { ref, reactive, computed, watch, onMounted, nextTick, useTemplateRef } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { useQuasar } from "quasar";
 import { useI18n } from "vue-i18n";
@@ -356,7 +385,6 @@ import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePick
 import DefaultFilePicker from "src/components/defaults/DefaultFilePicker.vue";
 import DefaultTable from "src/components/defaults/DefaultTable.vue";
 import PartnerAgreementCategorySelect from "src/components/selects/PartnerAgreementCategorySelect.vue";
-import ParceiroSelect from "src/components/selects/ParceiroSelect.vue";
 import CitySelect from "src/components/selects/CitySelect.vue";
 import StateSelect from "src/components/selects/StateSelect.vue";
 
@@ -415,7 +443,7 @@ const tabsItems = computed(() => [
 const formDadosRef = useTemplateRef("formDadosRef");
 const logoFile = ref(null);
 const selectedCategory = ref(null);
-const selectedUser = ref(null);
+const newUser = reactive({ name: "", email: "", password: "" });
 
 const {
   form: formDados,
@@ -425,7 +453,6 @@ const {
   company_name:        "",
   cnpj:                "",
   category_id:         null,
-  user_id:             null,
   responsible:         "",
   discount_percentage: null,
   description:         "",
@@ -441,17 +468,18 @@ watch(selectedCategory, (val) => {
   formDados.category_id = val?.value ?? null;
 });
 
-watch(selectedUser, (val) => {
-  formDados.user_id = val?.value ?? null;
-});
-
 const saveDados = async () => {
   await execDados(async () => {
     let savedPartner;
     if (partnerId.value) {
       savedPartner = await updatePartnerAgreement(partnerId.value, updatedDados.value);
     } else {
-      savedPartner = await createPartnerAgreement({ ...formDados });
+      savedPartner = await createPartnerAgreement({
+        ...formDados,
+        user_name:     newUser.name,
+        user_email:    newUser.email,
+        user_password: newUser.password,
+      });
       await router.replace({ name: "ParceiroCadastroPage", params: { id: savedPartner.id } });
     }
     if (logoFile.value instanceof File) {
@@ -642,7 +670,6 @@ const populateForms = (p) => {
   formDados.company_name        = p.company_name        ?? "";
   formDados.cnpj                = p.cnpj                ?? "";
   formDados.category_id         = p.category_id         ?? null;
-  formDados.user_id             = p.user_id             ?? null;
   formDados.responsible         = p.responsible         ?? "";
   formDados.discount_percentage = p.discount_percentage != null ? String(p.discount_percentage) : null;
   formDados.description         = p.description         ?? "";
@@ -651,10 +678,6 @@ const populateForms = (p) => {
     ? { label: p.category.name, value: p.category.id }
     : null;
 
-  selectedUser.value = p.user
-    ? { label: p.user.name, value: p.user.id }
-    : null;
-
   formContato.email    = p.email    ?? "";
   formContato.phone    = p.phone    ?? "";
   formContato.whatsapp = p.whatsapp ?? "";
@@ -685,6 +708,7 @@ onMounted(async () => {
     } catch {
       $q.notify({ type: "negative", message: t("http.errors.failed") });
     }
+    if (activeTab.value === "servicos") loadServices();
   }
 });
 

+ 1 - 0
src/pages/parceiros-convenios/ParceiroDadosPage.vue

@@ -625,6 +625,7 @@ onMounted(async () => {
     const p = await getMyPartnerAgreement();
     partner.value = p;
     populateForms(p);
+    if (activeTab.value === "servicos") await loadServices();
   } catch {
     $q.notify({ type: "negative", message: t("http.errors.failed") });
   } finally {

+ 1 - 3
src/pages/parceiros-convenios/ValidarCarteirinhaPage.vue

@@ -141,9 +141,7 @@ const onValidate = async () => {
 
     const response = await validateAssociate({
 
-      cpf: search.value,
-      registration: search.value,
-      name: search.value,
+      search: search.value,
 
     });
 

+ 7 - 2
src/pages/relatorios/RelatoriosPage.vue

@@ -34,6 +34,7 @@
 
     <div v-if="activeTab === 'novos-associados'">
       <DefaultTableServerSide
+        ref="tableRef"
         :key="tableKey"
         :columns="columnsNovosAssociados"
         :api-call="getNovoAssociadosPaginated"
@@ -44,6 +45,7 @@
 
     <div v-else-if="activeTab === 'contatos-associados'">
       <DefaultTableServerSide
+        ref="tableRef"
         :key="tableKey"
         :columns="columnsContatos"
         :api-call="getContatosAssociadosPaginated"
@@ -54,6 +56,7 @@
 
     <div v-else-if="activeTab === 'exclusoes-mes'">
       <DefaultTableServerSide
+        ref="tableRef"
         :key="tableKey"
         :columns="columnsExclusoes"
         :api-call="getExclusoesMesPaginated"
@@ -65,7 +68,7 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from "vue";
+import { ref, computed, onMounted, useTemplateRef } from "vue";
 import { useQuasar } from "quasar";
 import { useI18n } from "vue-i18n";
 import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
@@ -84,6 +87,7 @@ const { t } = useI18n();
 const activeTab = ref("novos-associados");
 const tableKey = ref(0);
 const exportLoading = ref(false);
+const tableRef = useTemplateRef("tableRef");
 const counters = ref({
   novos_associados: undefined,
   contatos: undefined,
@@ -191,7 +195,8 @@ const selectTab = (name) => {
 const onExport = async () => {
   exportLoading.value = true;
   try {
-    await exportRelatorio(activeTab.value);
+    const search = tableRef.value?.getFilter() || undefined;
+    await exportRelatorio(activeTab.value, search);
   } catch {
     $q.notify({ type: "negative", message: t("http.errors.failed") });
   } finally {

+ 9 - 9
src/stores/navigation.js

@@ -91,15 +91,15 @@ export const navigationStore = defineStore("navigation", () => {
       permissionScope: "associado.perfil",
       allowedTypes: ["associado"],
     },
-    // {
-    //   type: "single",
-    //   title: "ui.navigation.carteirinha",
-    //   name: "CarteirinhaPage",
-    //   icon: "mdi-card-account-details-outline",
-    //   permission: false,
-    //   permissionScope: "associado.carteirinha",
-    //   allowedTypes: ["associado"],
-    // },
+    {
+      type: "single",
+      title: "ui.navigation.carteirinha",
+      name: "CarteirinhaPage",
+      icon: "mdi-card-account-details-outline",
+      permission: false,
+      permissionScope: "associado.carteirinha",
+      allowedTypes: ["associado"],
+    },
     {
       type: "single",
       title: "ui.navigation.convenios",