Files
2026-04-28 20:59:51 +03:30

242 lines
8.2 KiB
Vue

<script setup lang="ts">
// meta
useSeoMeta({
title: "پنل کاربری اعلان ها",
});
definePageMeta({
middleware: "check-is-logged-in",
layout: "profile",
});
// imports
import { usePushNotifications } from "~/composables/global/usePushNotifications";
import useSubscribeNotification from "~/composables/api/notifications/useSubscribeNotification";
import useGetAllNotifications from "~/composables/api/account/useGetAllNotifications";
import { useAppParams } from "~/composables/global/useAppParams";
// state
const subscribe = ref(false);
const { status, sort } = useAppParams();
const sortFilters = ref([
{
title: "اخبار",
value: "NEWS",
},
{
title: "اعلانات کاربر",
value: "USER_NOTIF",
},
]);
const statusFilters = ref([
{
title: "خوانده شده",
value: "read",
},
{
title: "خوانده نشده",
value: "not_read",
},
]);
// queries
const {
isSupported,
subscribe: notificationSubsribe,
unsubscribe: notificationUnSubsribe,
subscription,
} = usePushNotifications();
const { isPending: subscribeNotificationIsPending } = useSubscribeNotification();
// computeds
const hasNotifications = computed(() => data.value && data.value.count > 0);
const { data, isLoading: notificationsIsLoading } = useGetAllNotifications();
const notifications = computed(() => {
return data.value?.results.flat();
});
const paginationData = computed(() => {
return data.value?.results.map((_, i: number) => {
return { type: "page", value: i };
});
});
// watch
watch(
() => subscribe.value,
(nv) => {
if (!!subscription && nv) {
notificationSubsribe();
} else {
notificationUnSubsribe();
}
}
);
</script>
<template>
<section class="w-full flex flex-col gap-5">
<ProfilePageTitle
title="اعلان های شما"
icon="ci:bi-bell"
/>
<div
v-if="isSupported"
class="w-fill flex items-center justify-between py-5 lg:p-5 pt-0 border-b border-slate-200 gap-5"
>
<div class="flex items-start justify-start gap-3">
<Icon
name="ci:bi-bell"
size="20"
/>
<div class="flex flex-col gap-1 pb-0.5">
<span class="text-sm"> دریافت مستقیم اعلانات </span>
<span class="text-xs text-slate-500 leading-[175%]">
اعلانات حساب شما به صورت مستقیم به دستگاه شما ارسال می شود
</span>
</div>
</div>
<div class="flex items-center justify-end gap-3">
<Switch v-model="subscribe" />
<Icon
v-if="subscribeNotificationIsPending"
name="ci:svg-spinners-180-ring-with-bg"
size="20"
/>
</div>
</div>
<div class="w-full flex items-center justify-between lg:px-5">
<span class="whitespace-pre max-lg:hidden"> 1 اعلان </span>
<div class="max-lg:w-full flex items-center justify-end gap-8">
<div class="flex items-center justify-start gap-3">
<span class="text-xs lg:text-sm">فیلتر بر اساس</span>
<Select
v-model="sort"
triggerRootClass="!py-2.5"
class="w-[6rem]"
>
<template #content>
<SelectGroup>
<SelectItem
v-for="(category, index) in sortFilters"
:key="index"
class="text-xs leading-none w-full rounded-sm py-4 lg:py-5 flex items-center justify-between h-[25px] pr-[12px] relative select-none data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-slate-300 data-[highlighted]:text-black"
:value="category.value"
>
<SelectItemIndicator
class="absolute left-0 w-[25px] inline-flex items-center justify-center"
>
<Icon
name="ci:bi-check"
size="20"
/>
</SelectItemIndicator>
<SelectItemText class="text-end font-iran-yekan-x text-xs lg:text-sm">
{{ category.title }}
</SelectItemText>
</SelectItem>
</SelectGroup>
</template>
</Select>
</div>
<div class="flex items-center justify-start gap-3">
<span class="text-xs lg:text-sm">وضعیت</span>
<Select
v-model="status"
triggerRootClass="!py-2.5"
class="w-[6rem]"
>
<template #content>
<SelectGroup>
<SelectItem
v-for="(category, index) in statusFilters"
:key="index"
class="text-xs leading-none w-full rounded-sm py-4 lg:py-5 flex items-center justify-between h-[25px] pr-[12px] relative select-none data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-slate-300 data-[highlighted]:text-black"
:value="category.value"
>
<SelectItemIndicator
class="absolute left-0 w-[25px] inline-flex items-center justify-center"
>
<Icon
name="ci:bi-check"
size="20"
/>
</SelectItemIndicator>
<SelectItemText class="text-end font-iran-yekan-x text-xs lg:text-sm">
{{ category.title }}
</SelectItemText>
</SelectItem>
</SelectGroup>
</template>
</Select>
</div>
</div>
</div>
<div
v-if="notificationsIsLoading"
class="flex flex-col gap-6 w-full"
>
<Skeleton
v-for="i in 3"
class="w-full !h-[8rem] !rounded-xl"
/>
</div>
<template v-else>
<div
v-if="!hasNotifications && !notificationsIsLoading"
class="flex flex-grow w-full"
v-auto-animate
>
<Placeholder
class="!w-full !py-[5rem]"
icon="ci:bi-ticket"
title="اعلانی یافت نشد"
/>
</div>
<div
v-else
class="flex flex-col gap-6 w-full"
>
<Notification
v-for="(notification, index) in notifications"
:key="index"
:data="notification"
/>
</div>
</template>
<div
v-if="data?.count! > 7"
class="w-full flex-center py-10"
>
<Pagination
:items="paginationData"
:total="data?.count!"
/>
</div>
</section>
</template>
<style scoped></style>