|
@@ -10,50 +10,15 @@
|
|
|
{{ $t('notification.empty') }}
|
|
{{ $t('notification.empty') }}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div v-else class="notif-list q-px-md">
|
|
|
|
|
- <div
|
|
|
|
|
|
|
+ <div v-else class="notifications-grid q-px-md">
|
|
|
|
|
+ <NotificationCard
|
|
|
v-for="item in pagedItems"
|
|
v-for="item in pagedItems"
|
|
|
:key="item.id"
|
|
:key="item.id"
|
|
|
- class="notif-item"
|
|
|
|
|
- :class="{ 'notif-item--unread': !item.read }"
|
|
|
|
|
|
|
+ :notification="item.notification"
|
|
|
|
|
+ :unread="!item.read"
|
|
|
|
|
+ :date="item.created_at"
|
|
|
@click="onRead(item)"
|
|
@click="onRead(item)"
|
|
|
- >
|
|
|
|
|
- <!-- Left: small image + date below -->
|
|
|
|
|
- <div class="notif-item__left">
|
|
|
|
|
- <div class="notif-item__img-wrap">
|
|
|
|
|
- <img
|
|
|
|
|
- v-if="imageUrl(item)"
|
|
|
|
|
- :src="imageUrl(item)"
|
|
|
|
|
- alt=""
|
|
|
|
|
- class="notif-item__img"
|
|
|
|
|
- />
|
|
|
|
|
- <div v-else class="notif-item__placeholder flex flex-center">
|
|
|
|
|
- <q-icon
|
|
|
|
|
- name="mdi-bell-outline"
|
|
|
|
|
- size="24px"
|
|
|
|
|
- :color="item.read ? 'grey-4' : 'violet-normal'"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <span class="notif-item__date text-violet-normal">{{ formatDate(item.created_at) }}</span>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- Right: title + message -->
|
|
|
|
|
- <div class="notif-item__content ">
|
|
|
|
|
- <div class="notif-item__title" :class="{ 'notif-item__title--read': item.read }">
|
|
|
|
|
- {{ item.notification?.title }}
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="notif-item__message">{{ item.notification?.message }}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- Unread dot top-right -->
|
|
|
|
|
- <q-badge
|
|
|
|
|
- v-if="!item.read"
|
|
|
|
|
- color="violet-normal"
|
|
|
|
|
- rounded
|
|
|
|
|
- class="notif-item__dot"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="totalPages > 1" class="flex flex-center q-mt-lg">
|
|
<div v-if="totalPages > 1" class="flex flex-center q-mt-lg">
|
|
@@ -73,13 +38,12 @@
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { ref, computed, onMounted } from "vue";
|
|
import { ref, computed, onMounted } from "vue";
|
|
|
import { useQuasar } from "quasar";
|
|
import { useQuasar } from "quasar";
|
|
|
-import { useI18n } from "vue-i18n";
|
|
|
|
|
import { getMyNotificationsAssociado } from "src/api/notification";
|
|
import { getMyNotificationsAssociado } from "src/api/notification";
|
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
|
import NotificationDetailDialog from "src/components/NotificationDetailDialog.vue";
|
|
import NotificationDetailDialog from "src/components/NotificationDetailDialog.vue";
|
|
|
|
|
+import NotificationCard from "src/components/NotificationCard.vue";
|
|
|
|
|
|
|
|
const $q = useQuasar();
|
|
const $q = useQuasar();
|
|
|
-const { t } = useI18n();
|
|
|
|
|
|
|
|
|
|
const loading = ref(true);
|
|
const loading = ref(true);
|
|
|
const notifications = ref([]);
|
|
const notifications = ref([]);
|
|
@@ -93,26 +57,6 @@ const pagedItems = computed(() => {
|
|
|
return notifications.value.slice(start, start + PER_PAGE);
|
|
return notifications.value.slice(start, start + PER_PAGE);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const imageUrl = (item) => {
|
|
|
|
|
- const media = item.notification?.media?.[0]?.url;
|
|
|
|
|
- if (media) return media;
|
|
|
|
|
- const direct = 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 d = new Date(dateStr);
|
|
|
|
|
- const today = new Date();
|
|
|
|
|
- const isToday =
|
|
|
|
|
- d.getDate() === today.getDate() &&
|
|
|
|
|
- d.getMonth() === today.getMonth() &&
|
|
|
|
|
- d.getFullYear() === today.getFullYear();
|
|
|
|
|
- if (isToday) return t("common.terms.today");
|
|
|
|
|
- return d.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric" });
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
const onRead = (item) => {
|
|
const onRead = (item) => {
|
|
|
$q.dialog({ component: NotificationDetailDialog, componentProps: { item } }).onOk((markedId) => {
|
|
$q.dialog({ component: NotificationDetailDialog, componentProps: { item } }).onOk((markedId) => {
|
|
|
if (markedId) {
|
|
if (markedId) {
|
|
@@ -143,110 +87,4 @@ onMounted(async () => {
|
|
|
overflow-x: hidden;
|
|
overflow-x: hidden;
|
|
|
padding-bottom: 16px;
|
|
padding-bottom: 16px;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-.notif-list {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- padding-top: 8px;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-.notif-item {
|
|
|
|
|
- background: white;
|
|
|
|
|
- border-radius: 12px;
|
|
|
|
|
- padding: 14px;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: row;
|
|
|
|
|
- align-items: flex-start;
|
|
|
|
|
- gap: 14px;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.07);
|
|
|
|
|
- position: relative;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- transition: box-shadow 0.2s;
|
|
|
|
|
-
|
|
|
|
|
- &:hover {
|
|
|
|
|
- box-shadow: 0 4px 14px rgba(102, 29, 117, 0.14);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &--unread {
|
|
|
|
|
- border-left: 3px solid vars.$violet-normal;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__left {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- flex-direction: column;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 6px;
|
|
|
|
|
- flex-shrink: 0;
|
|
|
|
|
- width: 68px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__img-wrap {
|
|
|
|
|
- width: 68px;
|
|
|
|
|
- height: 68px;
|
|
|
|
|
- border-radius: 10px;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- background: vars.$violet-light;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__img {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- object-fit: cover;
|
|
|
|
|
- display: block;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__placeholder {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- height: 100%;
|
|
|
|
|
- background: vars.$violet-light;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__date {
|
|
|
|
|
- font-size: 10px;
|
|
|
|
|
- color: vars.$violet-normal;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- line-height: 1.3;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__content {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- min-width: 0;
|
|
|
|
|
- padding-right: 10px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__title {
|
|
|
|
|
- font-size: 14px;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- color: vars.$violet-normal;
|
|
|
|
|
- line-height: 1.3;
|
|
|
|
|
- margin-bottom: 5px;
|
|
|
|
|
-
|
|
|
|
|
- &--read {
|
|
|
|
|
- color: vars.$violet-dark;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__message {
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- color: vars.$color-text-2;
|
|
|
|
|
- line-height: 1.5;
|
|
|
|
|
- display: -webkit-box;
|
|
|
|
|
- -webkit-line-clamp: 3;
|
|
|
|
|
- line-clamp: 3;
|
|
|
|
|
- -webkit-box-orient: vertical;
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- &__dot {
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- top: 14px;
|
|
|
|
|
- right: 14px;
|
|
|
|
|
- width: 8px;
|
|
|
|
|
- height: 8px;
|
|
|
|
|
- min-height: unset;
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
</style>
|
|
</style>
|