242 lines
8.1 KiB
Vue
242 lines
8.1 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="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="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="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="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="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="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>
|