mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-30 14:30:08 +08:00
Improve notifications page
Add type icons, fix mark as read not updating the current list
This commit is contained in:
parent
dc817573ca
commit
542a4efbe3
@ -1,13 +1,21 @@
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{
|
||||
to?: string | object;
|
||||
href?: string;
|
||||
}>();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
to?: string | object;
|
||||
href?: string;
|
||||
activeUnderline?: boolean;
|
||||
}>(),
|
||||
{
|
||||
activeUnderline: true,
|
||||
to: undefined,
|
||||
href: undefined,
|
||||
}
|
||||
);
|
||||
const classes = "color-primary font-bold hover:(underline)";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-link v-if="to" :to="to" :class="classes" v-bind="$attrs" active-class="underline">
|
||||
<router-link v-if="to" :to="to" :class="classes" v-bind="$attrs" :active-class="props.activeUnderline ? 'underline' : ''">
|
||||
<slot></slot>
|
||||
</router-link>
|
||||
<a v-else :href="href" :class="classes" v-bind="$attrs">
|
||||
|
@ -236,12 +236,12 @@ function isRecent(date: string): boolean {
|
||||
:key="notification.id"
|
||||
:class="'text-sm flex shadow-0 p-3 pt-2 pr-4 inline-flex items-center ' + (!notification.read ? 'bg-blue-100 dark:bg-slate-700' : '')"
|
||||
>
|
||||
<div class="text-lg mr-2">
|
||||
<span class="text-lg mr-2">
|
||||
<IconMdiInformationOutline v-if="notification.type === 'info'" class="text-lightBlue-600" />
|
||||
<IconMdiCheck v-else-if="notification.type === 'success'" class="text-lime-600" />
|
||||
<IconMdiAlertOutline v-else-if="notification.type === 'warning'" class="text-red-600" />
|
||||
<IconMdiMessageOutline v-else-if="notification.type === 'neutral'" />
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<router-link v-if="notification.action" :to="'/' + notification.action" active-class="" @click="markNotificationRead(notification)">
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
|
@ -29,11 +29,11 @@ const route = useRoute();
|
||||
|
||||
<TreeView :items="project.pages" item-key="slug" :open="open">
|
||||
<template #item="{ item }">
|
||||
<Link v-if="item.home" :to="`/${route.params.user}/${route.params.project}`" exact class="inline-flex items-center">
|
||||
<Link v-if="item.home" :to="`/${route.params.user}/${route.params.project}`" exact class="inline-flex items-center" active-underline>
|
||||
<IconMdiHome class="mr-1" />
|
||||
{{ item.name }}
|
||||
</Link>
|
||||
<Link v-else :to="`/${route.params.user}/${route.params.project}/pages/${item.slug}`" exact> {{ item.name }}</Link>
|
||||
<Link v-else :to="`/${route.params.user}/${route.params.project}/pages/${item.slug}`" exact active-underline> {{ item.name }}</Link>
|
||||
</template>
|
||||
</TreeView>
|
||||
</Card>
|
||||
|
@ -74,7 +74,7 @@ useHead(useSeo(props.user.name, props.user.tagline, route, avatarUrl(props.user.
|
||||
<template>
|
||||
<UserHeader :user="user" :organization="organization" />
|
||||
<div class="flex gap-4 flex-basis-full flex-col md:flex-row">
|
||||
<div class="flex-basis-full flex-grow md:max-w-2/3 md:min-w-1/3">
|
||||
<div class="flex-basis-full flex flex-col gap-2 flex-grow md:max-w-2/3 md:min-w-1/3">
|
||||
<ProjectList :projects="projects"></ProjectList>
|
||||
</div>
|
||||
<div class="flex-basis-full flex-grow md:max-w-1/3 md:min-w-1/3">
|
||||
|
@ -13,6 +13,10 @@ import { useNotificationStore } from "~/store/notification";
|
||||
import Card from "~/components/design/Card.vue";
|
||||
import Button from "~/components/design/Button.vue";
|
||||
import InputSelect from "~/components/ui/InputSelect.vue";
|
||||
import IconMdiAlertOutline from "~icons/mdi/alert-outline";
|
||||
import IconMdiInformationOutline from "~icons/mdi/information-outline";
|
||||
import IconMdiMessageOutline from "~icons/mdi/message-outline";
|
||||
import IconMdiCheck from "~icons/mdi/check";
|
||||
|
||||
const ctx = useContext();
|
||||
const i18n = useI18n();
|
||||
@ -70,23 +74,21 @@ function markAllAsRead() {
|
||||
}
|
||||
|
||||
async function markNotificationRead(notification: HangarNotification, router = true) {
|
||||
const result = await useInternalApi(`notifications/${notification.id}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
if (!result) return;
|
||||
delete notifications.value[notifications.value.findIndex((n) => n.id === notification.id)];
|
||||
await useInternalApi(`notifications/${notification.id}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
notification.read = true;
|
||||
if (notification.action && router) {
|
||||
await useRouter().push(notification.action);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateInvite(invite: Invite, status: "accept" | "decline" | "unaccept") {
|
||||
const result = await useInternalApi(`invites/${invite.type}/${invite.roleTableId}/${status}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
if (!result) return;
|
||||
await useInternalApi(`invites/${invite.type}/${invite.roleTableId}/${status}`, true, "post").catch((e) => handleRequestError(e, ctx, i18n));
|
||||
if (status === "accept") {
|
||||
invite.accepted = true;
|
||||
} else if (status === "unaccept") {
|
||||
invite.accepted = false;
|
||||
} else {
|
||||
delete invites.value[invite.type][invites.value[invite.type].indexOf(invite)];
|
||||
invites.value[invite.type] = invites.value[invite.type].filter((i) => i.roleTableId !== invite.roleTableId);
|
||||
}
|
||||
notificationStore.success(i18n.t(`notifications.invite.msgs.${status}`, [invite.name]));
|
||||
await useRouter().go(0);
|
||||
@ -108,9 +110,17 @@ async function updateInvite(invite: Invite, status: "accept" | "decline" | "unac
|
||||
</Button>
|
||||
</div>
|
||||
<Card v-for="notification in filteredNotifications" :key="notification.id" :class="'text-' + notification.type + ' flex shadow-0'">
|
||||
<span class="flex-grow">
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
</span>
|
||||
<div class="inline-flex items-center">
|
||||
<span class="text-lg mr-2">
|
||||
<IconMdiInformationOutline v-if="notification.type === 'info'" class="text-lightBlue-600" />
|
||||
<IconMdiCheck v-else-if="notification.type === 'success'" class="text-lime-600" />
|
||||
<IconMdiAlertOutline v-else-if="notification.type === 'warning'" class="text-red-600" />
|
||||
<IconMdiMessageOutline v-else-if="notification.type === 'neutral'" />
|
||||
</span>
|
||||
<span class="flex-grow">
|
||||
{{ i18n.t(notification.message[0], notification.message.slice(1)) }}
|
||||
</span>
|
||||
</div>
|
||||
<Button v-if="!notification.read" class="ml-2" @click="markNotificationRead(notification)"><IconMdiCheck /></Button>
|
||||
</Card>
|
||||
<div v-if="!filteredNotifications.length" class="text-red-500 text-lg mt-4">
|
||||
|
Loading…
Reference in New Issue
Block a user