Ver código fonte

correcao notificacoes para exibir imagem corretamente + abrir modal com informacoes completas

Gustavo Zanatta 1 mês atrás
pai
commit
6d9970a93a

+ 137 - 0
src/components/NotificationDetailDialog.vue

@@ -0,0 +1,137 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="notif-detail-card">
+      <q-card-section class="row items-center q-pb-none">
+        <div class="text-h6 text-violet-normal ellipsis" style="max-width: calc(100% - 48px)">
+          {{ item.notification?.title }}
+        </div>
+        <q-space />
+        <q-btn icon="mdi-close" flat round dense @click="handleClose" />
+      </q-card-section>
+
+      <q-separator class="q-mt-sm" />
+
+      <q-card-section class="q-pt-md notif-detail-card__scroll">
+        <div v-if="imageUrl" class="notif-detail-card__image q-mb-md">
+          <img :src="imageUrl" alt="" class="notif-detail-card__img" />
+        </div>
+
+        <div class="text-body2 text-grey-8 notif-detail-card__message">
+          {{ item.notification?.message }}
+        </div>
+
+        <div class="text-caption text-grey-5 q-mt-md">
+          {{ formatDate(item.created_at) }}
+        </div>
+      </q-card-section>
+
+      <q-separator />
+
+      <q-card-actions align="right" class="q-pa-sm">
+        <q-btn
+          flat
+          color="violet-normal"
+          :label="$t('common.actions.close')"
+          @click="handleClose"
+        />
+      </q-card-actions>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from "vue";
+import { useI18n } from "vue-i18n";
+import { useDialogPluginComponent } from "quasar";
+import { userStore } from "src/stores/user";
+import {
+  markNotificationAsReadAssociado,
+  markNotificationAsReadParceiro,
+} from "src/api/notification";
+
+const props = defineProps({
+  item: { type: Object, required: true },
+});
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
+
+const { t } = useI18n();
+const store = userStore();
+const markedReadId = ref(null);
+
+const imageUrl = computed(() => {
+  const media = props.item.notification?.media?.[0]?.url;
+  if (media) return media;
+  const direct = props.item.notification?.image_url;
+  if (!direct) return null;
+  return direct.startsWith("http") ? direct : (process.env.API_URL ?? "") + direct;
+});
+
+const formatDate = (dateStr) => {
+  if (!dateStr) return "";
+  const date = new Date(dateStr);
+  const today = new Date();
+  const isToday =
+    date.getDate() === today.getDate() &&
+    date.getMonth() === today.getMonth() &&
+    date.getFullYear() === today.getFullYear();
+  if (isToday) return t("common.terms.today");
+  return date.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric" });
+};
+
+const handleClose = () => {
+  onDialogOK(markedReadId.value);
+};
+
+onMounted(async () => {
+  if (props.item.read) return;
+  try {
+    if (store.isAssociado) {
+      await markNotificationAsReadAssociado(props.item.id);
+    } else if (store.isParceiro) {
+      await markNotificationAsReadParceiro(props.item.id);
+    }
+    markedReadId.value = props.item.id;
+  } catch (e) {
+    console.error(e);
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.notif-detail-card {
+  width: 90vw;
+  max-width: 600px;
+  min-width: 300px;
+
+  &__scroll {
+    max-height: 70vh;
+    overflow-y: auto;
+  }
+
+  &__image {
+    width: 100%;
+    border-radius: 8px;
+    overflow: hidden;
+    background: #f0e8f1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
+  &__img {
+    width: 100%;
+    max-height: 350px;
+    object-fit: contain;
+    display: block;
+  }
+
+  &__message {
+    white-space: pre-wrap;
+    word-break: break-word;
+    line-height: 1.6;
+  }
+}
+</style>

+ 14 - 15
src/components/UnreadNotificationsDialog.vue

@@ -31,7 +31,7 @@
               bordered
               class="notif-card"
               :class="{ 'notif-card--unread': !item.read }"
-              @click="onRead(item)"
+              @click="openDetail(item)"
             >
               <div class="notif-card__image">
                 <img
@@ -102,18 +102,19 @@
       </q-card-actions>
     </q-card>
   </q-dialog>
+
 </template>
 
 <script setup>
 import { ref, computed, watch } from "vue";
 import { useI18n } from "vue-i18n";
+import { useQuasar } from "quasar";
 import { userStore } from "src/stores/user";
 import {
   getMyUnreadNotificationsAssociado,
-  markNotificationAsReadAssociado,
   getMyUnreadNotificationsParceiro,
-  markNotificationAsReadParceiro,
 } from "src/api/notification";
+import NotificationDetailDialog from "src/components/NotificationDetailDialog.vue";
 
 const props = defineProps({
   modelValue: { type: Boolean, required: true },
@@ -122,6 +123,7 @@ const props = defineProps({
 const emit = defineEmits(["update:modelValue"]);
 
 const { t } = useI18n();
+const $q = useQuasar();
 const store = userStore();
 
 const loading = ref(false);
@@ -164,18 +166,15 @@ const formatDate = (dateStr) => {
   return date.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric" });
 };
 
-const onRead = async (item) => {
-  if (item.read) return;
-  try {
-    if (store.isAssociado) {
-      await markNotificationAsReadAssociado(item.id);
-    } else if (store.isParceiro) {
-      await markNotificationAsReadParceiro(item.id);
-    }
-    item.read = true;
-  } catch (e) {
-    console.error(e);
-  }
+const openDetail = (item) => {
+  $q.dialog({
+    component: NotificationDetailDialog,
+    componentProps: { item },
+  }).onOk((id) => {
+    if (!id) return;
+    const found = notifications.value.find((n) => n.id === id);
+    if (found) found.read = true;
+  });
 };
 
 const close = () => {

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

@@ -57,7 +57,8 @@
       "download_certificate": "Download certificate",
       "download_boleto": "Download Boleto",
       "copy_paste_code": "Copy and paste the code below to make the payment",
-      "go_home": "Go Home"
+      "go_home": "Go Home",
+      "close": "Fechar"
     },
     "terms": {
       "actions": "Actions",

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

@@ -57,7 +57,8 @@
       "download_certificate": "Descargar certificado",
       "download_boleto": "Descargar Boleto",
       "copy_paste_code": "Copie y pegue el código a continuación para realizar el pago",
-      "go_home": "Ir al Inicio"
+      "go_home": "Ir al Inicio",
+      "close": "Fechar"
     },
     "terms": {
       "actions": "Acciones",

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

@@ -57,7 +57,8 @@
       "download_certificate": "Baixar certificado",
       "download_boleto": "Baixar Boleto",
       "copy_paste_code": "Copie e cole o código abaixo para efetuar o pagamento",
-      "go_home": "Ir para o Início"
+      "go_home": "Ir para o Início",
+      "close": "Fechar"
     },
     "terms": {
       "actions": "Ações",