1
0
Fork 0
polaris-task-force/src/lib/notifications/index.ts

91 lines
2.6 KiB
TypeScript

import { broadcastToUser } from "@/lib/realtime/bus";
type PayloadType = Awaited<ReturnType<typeof import("payload").getPayload>>;
export interface NotifyInput {
userId: number;
type?: string;
title: string;
message?: string;
link?: string;
}
/** Create an in-app notification for a user. Fire-and-forget: failures are logged, not thrown. */
export async function notifyUser(payload: PayloadType, input: NotifyInput): Promise<void> {
try {
const target = await payload.findByID({
collection: "users",
id: input.userId,
depth: 0,
overrideAccess: true,
});
const prefs = (
target as {
preferences?: {
notifications?: { mutedAll?: boolean | null; mutedTypes?: (string | null)[] | null };
};
}
).preferences?.notifications;
if (prefs?.mutedAll) return;
if (input.type && prefs?.mutedTypes?.includes(input.type)) return;
await payload.create({
collection: "user-notifications",
data: {
user: input.userId,
type: input.type,
title: input.title,
message: input.message,
link: input.link,
read: false,
},
overrideAccess: true,
depth: 0,
});
broadcastToUser("notification", input.userId, { type: input.type ?? null });
} catch (err) {
console.error("[Notifications] Failed to create notification:", err);
}
}
/** Short display label for a notification type, or the raw type when unknown. */
export function notificationLabel(type?: string | null): string {
switch (type) {
case "market:offer":
return "New offer";
case "market:counter":
return "Counteroffer";
case "market:accept":
return "Offer accepted";
case "market:reject":
return "Offer rejected";
case "market:withdrawn":
return "Offer withdrawn";
case "market:closed":
return "Negotiations closed";
case "market:sold":
return "Listing sold";
case "market:expired":
return "Listing expired";
case "account:discord-request":
return "Discord request";
case "finance:deposit":
return "Bank deposit";
case "finance:withdraw":
return "Bank withdrawal";
case "finance:transfer":
return "Bank transfer";
case "shipment:completed":
return "Shipment completed";
case "ticket:created":
return "New ticket";
case "ticket:assigned":
return "Ticket assigned";
case "ticket:reply":
return "New reply";
case "ticket:status":
return "Ticket updated";
default:
return type ?? "Notification";
}
}