mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-04-11 07:25:42 -04:00
136 lines
3.7 KiB
TypeScript
136 lines
3.7 KiB
TypeScript
import { useHouseholdSelf } from "~/composables/use-households";
|
|
import { useGroupSelf } from "~/composables/use-groups";
|
|
import { useUserApi } from "~/composables/api";
|
|
|
|
export type AnnouncementMeta = {
|
|
title: string | undefined;
|
|
};
|
|
|
|
export type Announcement = {
|
|
key: string;
|
|
component: Component;
|
|
date: Date | undefined;
|
|
meta: AnnouncementMeta | undefined;
|
|
};
|
|
|
|
const _announcementsUnsorted = import.meta.glob<{ default: Component; meta?: AnnouncementMeta }>(
|
|
"~/components/Domain/Announcement/Announcements/*.vue",
|
|
{ eager: true },
|
|
);
|
|
const allAnnouncements: Announcement[] = Object.entries(_announcementsUnsorted)
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
.map(([path, mod]) => {
|
|
const key = path.split("/").at(-1)!.replace(".vue", "");
|
|
|
|
const parsed = new Date(key.split("_", 1)[0]!);
|
|
const date = isNaN(parsed.getTime()) ? undefined : parsed;
|
|
|
|
return {
|
|
key,
|
|
component: mod.default,
|
|
date,
|
|
meta: mod.meta,
|
|
};
|
|
});
|
|
|
|
const newAnnouncements = shallowRef<Announcement[]>([]);
|
|
|
|
function isWelcomeAnnouncement(key: string) {
|
|
return key === allAnnouncements.at(0)!.key;
|
|
}
|
|
|
|
export function useAnnouncements() {
|
|
const auth = useMealieAuth();
|
|
const api = useUserApi();
|
|
const { household } = useHouseholdSelf();
|
|
const { group } = useGroupSelf();
|
|
|
|
const announcementsEnabled = computed(
|
|
() =>
|
|
!!(
|
|
auth.user.value?.showAnnouncements
|
|
&& household.value?.preferences?.showAnnouncements
|
|
&& group.value?.preferences?.showAnnouncements
|
|
),
|
|
);
|
|
|
|
function updateUnreadAnnouncements(lastReadKey: string) {
|
|
newAnnouncements.value = allAnnouncements.filter(a => a.key > lastReadKey);
|
|
}
|
|
|
|
async function setLastRead(key: string) {
|
|
const user = auth.user.value!;
|
|
|
|
if (!user.lastReadAnnouncement && isWelcomeAnnouncement(key)) {
|
|
// The welcome announcement is a special case: it's shown to new users and
|
|
// all other announcements are marked as read when they view it
|
|
key = allAnnouncements.at(-1)!.key;
|
|
updateUnreadAnnouncements(key);
|
|
}
|
|
else {
|
|
// Only mark this specific announcement as read in the current session
|
|
newAnnouncements.value = newAnnouncements.value.filter(a => a.key !== key);
|
|
}
|
|
|
|
if (user.lastReadAnnouncement && key <= user.lastReadAnnouncement) {
|
|
// Don't update the last read announcement if it's older than the current one
|
|
return;
|
|
}
|
|
|
|
user.lastReadAnnouncement = key; // update immediately so we don't have to wait for the db
|
|
await api.users.updateOne(
|
|
user.id,
|
|
{
|
|
...user,
|
|
lastReadAnnouncement: key,
|
|
},
|
|
{ suppressAlert: true },
|
|
);
|
|
}
|
|
|
|
async function markAllAsRead() {
|
|
setLastRead(allAnnouncements.at(-1)!.key);
|
|
newAnnouncements.value = [];
|
|
}
|
|
|
|
function initUnreadAnnouncements() {
|
|
const user = auth.user.value;
|
|
|
|
// Only logged-in users can see announcements
|
|
if (!user || !allAnnouncements.length) {
|
|
newAnnouncements.value = [];
|
|
return;
|
|
}
|
|
|
|
// If a user has never seen an announcement, show them only the welcome announcement
|
|
if (!user.lastReadAnnouncement) {
|
|
newAnnouncements.value = [allAnnouncements.at(0)!];
|
|
return;
|
|
}
|
|
|
|
// Return all announcements newer than the last read announcement
|
|
updateUnreadAnnouncements(user.lastReadAnnouncement);
|
|
}
|
|
|
|
initUnreadAnnouncements();
|
|
|
|
// If the user changes, re-init
|
|
let lastUserId = auth.user.value?.id;
|
|
watch(auth.user, () => {
|
|
if (auth.user.value?.id === lastUserId) {
|
|
return;
|
|
}
|
|
|
|
lastUserId = auth.user.value?.id;
|
|
initUnreadAnnouncements();
|
|
});
|
|
|
|
return {
|
|
announcementsEnabled,
|
|
newAnnouncements,
|
|
allAnnouncements,
|
|
setLastRead,
|
|
markAllAsRead,
|
|
};
|
|
}
|