Files
outline/app/models/Notification.ts

200 lines
5.0 KiB
TypeScript

import { TFunction } from "i18next";
import { action, computed, observable } from "mobx";
import { NotificationEventType } from "@shared/types";
import {
collectionPath,
commentPath,
documentPath,
settingsPath,
} from "~/utils/routeHelpers";
import Collection from "./Collection";
import Comment from "./Comment";
import Document from "./Document";
import User from "./User";
import Model from "./base/Model";
import Field from "./decorators/Field";
import Relation from "./decorators/Relation";
class Notification extends Model {
static modelName = "Notification";
@Field
@observable
id: string;
/**
* The date the notification was marked as read.
*/
@Field
@observable
viewedAt: Date | null;
/**
* The date the notification was archived.
*/
@Field
@observable
archivedAt: Date | null;
/**
* The user that triggered the notification.
*/
@Relation(() => User)
actor?: User;
/**
* The document ID that the notification is associated with.
*/
documentId?: string;
/**
* The document that the notification is associated with.
*/
@Relation(() => Document, { onDelete: "cascade" })
document?: Document;
/**
* The collection ID that the notification is associated with.
*/
collectionId?: string;
/**
* The collection that the notification is associated with.
*/
@Relation(() => Collection, { onDelete: "cascade" })
collection?: Collection;
commentId?: string;
/**
* The comment that the notification is associated with.
*/
@Relation(() => Comment, { onDelete: "cascade" })
comment?: Comment;
/**
* The type of notification.
*/
event: NotificationEventType;
/**
* Mark the notification as read or unread
*
* @returns A promise that resolves when the notification has been saved.
*/
@action
toggleRead() {
this.viewedAt = this.viewedAt ? null : new Date();
return this.save();
}
/**
* Mark the notification as read
*
* @returns A promise that resolves when the notification has been saved.
*/
@action
markAsRead() {
if (this.viewedAt) {
return;
}
this.viewedAt = new Date();
return this.save();
}
/**
* Returns translated text that describes the notification
*
* @param t - The translation function
* @returns The event text
*/
eventText(t: TFunction): string {
switch (this.event) {
case NotificationEventType.PublishDocument:
return t("published");
case NotificationEventType.UpdateDocument:
case NotificationEventType.CreateRevision:
return t("edited");
case NotificationEventType.CreateCollection:
return t("created the collection");
case NotificationEventType.MentionedInDocument:
case NotificationEventType.MentionedInComment:
return t("mentioned you in");
case NotificationEventType.CreateComment:
return t("left a comment on");
case NotificationEventType.AddUserToDocument:
return t("shared");
case NotificationEventType.AddUserToCollection:
return t("invited you to");
default:
return this.event;
}
}
/**
* Returns the subject of the notification. This is the title of the associated
* document.
*
* @returns The subject
*/
get subject() {
if (this.documentId) {
return this.document?.title ?? "a document";
}
if (this.collectionId) {
return this.collection?.name ?? "a collection";
}
return "Unknown";
}
/**
* Returns the path to the model associated with the notification that can be
* used with the router.
*
* @returns The router path.
*/
@computed
get path() {
switch (this.event) {
case NotificationEventType.PublishDocument:
case NotificationEventType.UpdateDocument:
case NotificationEventType.CreateRevision: {
return this.document ? documentPath(this.document) : "";
}
case NotificationEventType.AddUserToCollection:
case NotificationEventType.CreateCollection: {
const collection = this.collectionId
? this.store.rootStore.collections.get(this.collectionId)
: undefined;
return collection ? collectionPath(collection.path) : "";
}
case NotificationEventType.AddUserToDocument:
case NotificationEventType.MentionedInDocument: {
return this.document?.path;
}
case NotificationEventType.MentionedInComment:
case NotificationEventType.CreateComment: {
return this.document && this.comment
? commentPath(this.document, this.comment)
: this.document?.path;
}
case NotificationEventType.InviteAccepted: {
return settingsPath("members");
}
case NotificationEventType.Onboarding:
case NotificationEventType.Features: {
return "";
}
case NotificationEventType.ExportCompleted: {
return settingsPath("export");
}
default:
this.event satisfies never;
return;
}
}
}
export default Notification;