diff --git a/app/atoms/notifications.ts b/app/atoms/notifications.ts index 61fe375d9..3b1d7cc13 100644 --- a/app/atoms/notifications.ts +++ b/app/atoms/notifications.ts @@ -1,3 +1,4 @@ +import type { User } from "@prisma/client"; import { atom } from "jotai"; import type { Icon } from "~/components/shared/icons-map"; @@ -13,6 +14,7 @@ export interface NotificationType { className?: string; }; time?: number; + senderId: User["id"] | null; } export const notificationAtom = atom({ @@ -24,6 +26,7 @@ export const notificationAtom = atom({ variant: "gray", className: "", }, + senderId: null, }); /** Opens the Toast and shows the notification */ diff --git a/app/components/shared/toast.tsx b/app/components/shared/toast.tsx index 63743859f..7b88a069e 100644 --- a/app/components/shared/toast.tsx +++ b/app/components/shared/toast.tsx @@ -24,7 +24,7 @@ export const Toaster = () => { }; /** New notification coming from the server */ - const newNotification = useEventSource("/api/sse/notification", { + const newNotification = useEventSource(`/api/sse/notification`, { event: "new-notification", }); /** When the stream sends us a new notification update the state so it displays */ diff --git a/app/routes/_layout+/assets.$assetId.note.tsx b/app/routes/_layout+/assets.$assetId.note.tsx index f71d1143f..c38ae20f6 100644 --- a/app/routes/_layout+/assets.$assetId.note.tsx +++ b/app/routes/_layout+/assets.$assetId.note.tsx @@ -41,6 +41,7 @@ export const action = async ({ request, params }: ActionArgs) => { title: "Note created", message: "Your note has been created successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); const note = await createNote({ ...result.data, @@ -68,6 +69,7 @@ export const action = async ({ request, params }: ActionArgs) => { title: "Note deleted", message: "Your note has been deleted successfully", icon: { name: "trash", variant: "error" }, + senderId: authSession.userId, }); const deleted = await deleteNote({ diff --git a/app/routes/_layout+/assets.$assetId.tsx b/app/routes/_layout+/assets.$assetId.tsx index 77811cbe8..b7b920d27 100644 --- a/app/routes/_layout+/assets.$assetId.tsx +++ b/app/routes/_layout+/assets.$assetId.tsx @@ -93,6 +93,7 @@ export async function action({ request, params }: ActionArgs) { title: "Asset deleted", message: "Your asset has been deleted successfully", icon: { name: "trash", variant: "error" }, + senderId: authSession.userId, }); return redirect(`/assets`, { diff --git a/app/routes/_layout+/assets.$assetId_.edit.tsx b/app/routes/_layout+/assets.$assetId_.edit.tsx index e7bf84635..9b9e4e4bf 100644 --- a/app/routes/_layout+/assets.$assetId_.edit.tsx +++ b/app/routes/_layout+/assets.$assetId_.edit.tsx @@ -111,6 +111,7 @@ export async function action({ request, params }: ActionArgs) { title: "Asset updated", message: "Your asset has been updated successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return json( diff --git a/app/routes/_layout+/assets.new.tsx b/app/routes/_layout+/assets.new.tsx index c2d457f14..872ee6140 100644 --- a/app/routes/_layout+/assets.new.tsx +++ b/app/routes/_layout+/assets.new.tsx @@ -99,9 +99,9 @@ export async function action({ request }: LoaderArgs) { title: "Asset created", message: "Your asset has been created successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); - if (asset.location) { await createNote({ content: `**${asset.user.firstName} ${asset.user.lastName}** set the location of **${asset.title}** to **${asset.location.name}**`, @@ -110,7 +110,7 @@ export async function action({ request }: LoaderArgs) { assetId: asset.id, }); } - + return redirect(`/assets`, { headers: { "Set-Cookie": await commitAuthSession(request, { authSession }), diff --git a/app/routes/_layout+/categories.new.tsx b/app/routes/_layout+/categories.new.tsx index 6c4368cce..625699802 100644 --- a/app/routes/_layout+/categories.new.tsx +++ b/app/routes/_layout+/categories.new.tsx @@ -64,6 +64,7 @@ export async function action({ request }: LoaderArgs) { title: "Category created", message: "Your category has been created successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return redirect(`/categories`, { diff --git a/app/routes/_layout+/categories.tsx b/app/routes/_layout+/categories.tsx index 788a59523..cc90840ce 100644 --- a/app/routes/_layout+/categories.tsx +++ b/app/routes/_layout+/categories.tsx @@ -72,6 +72,7 @@ export async function action({ request }: ActionArgs) { title: "Category deleted", message: "Your category has been deleted successfully", icon: { name: "trash", variant: "error" }, + senderId: userId, }); return json({ success: true }); diff --git a/app/routes/_layout+/locations.$locationId.tsx b/app/routes/_layout+/locations.$locationId.tsx index fabf1b82d..2a2e5c48b 100644 --- a/app/routes/_layout+/locations.$locationId.tsx +++ b/app/routes/_layout+/locations.$locationId.tsx @@ -112,6 +112,7 @@ export async function action({ request, params }: ActionArgs) { title: "Location deleted", message: "Your location has been deleted successfully", icon: { name: "trash", variant: "error" }, + senderId: authSession.userId, }); return redirect(`/locations`, { diff --git a/app/routes/_layout+/locations.$locationId_.edit.tsx b/app/routes/_layout+/locations.$locationId_.edit.tsx index 224ffcae4..d0c92bf36 100644 --- a/app/routes/_layout+/locations.$locationId_.edit.tsx +++ b/app/routes/_layout+/locations.$locationId_.edit.tsx @@ -96,6 +96,7 @@ export async function action({ request, params }: ActionArgs) { title: "Location updated", message: "Your location has been updated successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return json( diff --git a/app/routes/_layout+/locations.new.tsx b/app/routes/_layout+/locations.new.tsx index f6d5757e4..e5d35a3d5 100644 --- a/app/routes/_layout+/locations.new.tsx +++ b/app/routes/_layout+/locations.new.tsx @@ -95,6 +95,7 @@ export async function action({ request }: ActionArgs) { title: "Location created", message: "Your location has been created successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return redirect(`/locations/${location.id}`, { diff --git a/app/routes/_layout+/settings.user.tsx b/app/routes/_layout+/settings.user.tsx index 6e0f23793..b233ed759 100644 --- a/app/routes/_layout+/settings.user.tsx +++ b/app/routes/_layout+/settings.user.tsx @@ -107,6 +107,7 @@ export async function action({ request }: ActionArgs) { title: "User updated", message: "Your settings have been updated successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return json( { success: true }, diff --git a/app/routes/_layout+/tags.new.tsx b/app/routes/_layout+/tags.new.tsx index 133f295bf..be250fa8a 100644 --- a/app/routes/_layout+/tags.new.tsx +++ b/app/routes/_layout+/tags.new.tsx @@ -58,6 +58,7 @@ export async function action({ request }: LoaderArgs) { title: "Tag created", message: "Your tag has been created successfully", icon: { name: "success", variant: "success" }, + senderId: authSession.userId, }); return redirect(`/tags`, { diff --git a/app/routes/_layout+/tags.tsx b/app/routes/_layout+/tags.tsx index 2d4e46d6d..52d46c118 100644 --- a/app/routes/_layout+/tags.tsx +++ b/app/routes/_layout+/tags.tsx @@ -72,6 +72,7 @@ export async function action({ request }: ActionArgs) { title: "Tag deleted", message: "Your tag has been deleted successfully", icon: { name: "trash", variant: "error" }, + senderId: userId, }); return json({ success: true }); diff --git a/app/routes/api+/sse.notification.ts b/app/routes/api+/sse.notification.ts index 5ed4ae8af..6cb44eb02 100644 --- a/app/routes/api+/sse.notification.ts +++ b/app/routes/api+/sse.notification.ts @@ -5,11 +5,15 @@ import { requireAuthSession } from "~/modules/auth"; import { emitter } from "~/utils/emitter/emitter.server"; export async function loader({ request }: LoaderArgs) { - await requireAuthSession(request); + const authSession = await requireAuthSession(request); return eventStream(request.signal, function setup(send) { /** Notification is a strigified json object with the shape {@link Notification} */ function handle(notification: string) { + /** We only send the notification if the logged in userId is the same as the senderId. + * We do this to prevent other users receiving notifications + */ + if (authSession.userId !== JSON.parse(notification).senderId) return; send({ event: "new-notification", data: notification }); } emitter.on("notification", handle); diff --git a/app/utils/emitter/send-notification.server.ts b/app/utils/emitter/send-notification.server.ts index 48ad6b7d3..bbdebf33b 100644 --- a/app/utils/emitter/send-notification.server.ts +++ b/app/utils/emitter/send-notification.server.ts @@ -1,5 +1,6 @@ import type { NotificationType } from "~/atoms/notifications"; import { emitter } from "./emitter.server"; +// import { useUserData } from "~/hooks"; export function sendNotification( notification: Omit