diff --git a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
index 2eddf25dea..90ad061e96 100644
--- a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
+++ b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
@@ -1,10 +1,12 @@
import type { Notification as APINotification } from "@cap/web-api-contract";
+import type { ImageUpload } from "@cap/web-domain";
import { faComment, faEye, faReply } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import clsx from "clsx";
import moment from "moment";
import Link from "next/link";
import { markAsRead } from "@/actions/notifications/mark-as-read";
+import { SignedImageUrl } from "@/components/SignedImageUrl";
import type { NotificationType } from "@/lib/Notification";
type NotificationItemProps = {
@@ -45,17 +47,12 @@ export const NotificationItem = ({
>
{/* Avatar */}
- {notification.author.avatar ? (
-

- ) : (
-
- {notification.author.name.charAt(0)}
-
- )}
+
{notification.readAt === null && (
)}
diff --git a/apps/web/app/api/notifications/route.ts b/apps/web/app/api/notifications/route.ts
index 0ea8748bee..f27ee584d0 100644
--- a/apps/web/app/api/notifications/route.ts
+++ b/apps/web/app/api/notifications/route.ts
@@ -2,12 +2,13 @@ import { db } from "@cap/database";
import { getCurrentUser } from "@cap/database/auth/session";
import { notifications, users } from "@cap/database/schema";
import { Notification as APINotification } from "@cap/web-api-contract";
-import { and, ColumnBaseConfig, desc, eq, isNull, sql } from "drizzle-orm";
-import { MySqlColumn } from "drizzle-orm/mysql-core";
+import { ImageUploads } from "@cap/web-backend";
+import { and, desc, eq, isNull, sql } from "drizzle-orm";
+import { Effect } from "effect";
import { NextResponse } from "next/server";
-import { AvcProfileInfo } from "node_modules/@remotion/media-parser/dist/containers/avc/parse-avc";
import { z } from "zod";
import type { NotificationType } from "@/lib/Notification";
+import { runPromise } from "@/lib/server";
import { jsonExtractString } from "@/utils/sql";
const notificationDataSchema = z.object({
@@ -90,32 +91,46 @@ export async function GET() {
formattedCountResults[type] = Number(count);
});
- const formattedNotifications = notificationsWithAuthors
- .map(({ notification, author }) => {
- try {
- // all notifications currently require an author
- if (!author) return;
+ const formattedNotifications = await Effect.gen(function* () {
+ const imageUploads = yield* ImageUploads;
- return APINotification.parse({
- id: notification.id,
- type: notification.type,
- readAt: notification.readAt,
- videoId: notification.data.videoId,
- createdAt: notification.createdAt,
- data: notification.data,
- comment: notification.data.comment,
- author: {
- id: author.id,
- name: author.name ?? "Unknown",
- avatar: author.avatar,
- },
- });
- } catch (error) {
- console.error("Invalid notification data:", error);
- return null;
- }
- })
- .filter(Boolean);
+ return yield* Effect.all(
+ notificationsWithAuthors.map(({ notification, author }) =>
+ Effect.gen(function* () {
+ // all notifications currently require an author
+ if (!author) return null;
+
+ const resolvedAvatar = author.avatar
+ ? yield* imageUploads
+ .resolveImageUrl(author.avatar)
+ .pipe(Effect.catchAll(() => Effect.succeed(null)))
+ : null;
+
+ return APINotification.parse({
+ id: notification.id,
+ type: notification.type,
+ readAt: notification.readAt,
+ videoId: notification.data.videoId,
+ createdAt: notification.createdAt,
+ data: notification.data,
+ comment: notification.data.comment,
+ author: {
+ id: author.id,
+ name: author.name ?? "Unknown",
+ avatar: resolvedAvatar,
+ },
+ });
+ }).pipe(
+ Effect.catchAll((error) => {
+ console.error("Invalid notification data:", error);
+ return Effect.succeed(null);
+ }),
+ ),
+ ),
+ );
+ })
+ .pipe(runPromise)
+ .then((results) => results.filter(Boolean));
return NextResponse.json({
notifications: formattedNotifications,