From 2c3ef82f548e55a0da3120872beaff740a8c4ca8 Mon Sep 17 00:00:00 2001
From: ameer2468 <33054370+ameer2468@users.noreply.github.com>
Date: Thu, 23 Oct 2025 18:36:07 +0300
Subject: [PATCH 1/4] fix avatars in notifications
---
.../Notifications/NotificationItem.tsx | 18 ++---
apps/web/app/api/notifications/route.ts | 70 +++++++++++--------
2 files changed, 49 insertions(+), 39 deletions(-)
diff --git a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
index 2eddf25dea..5215423751 100644
--- a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
+++ b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
@@ -5,6 +5,7 @@ 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 +46,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..ca36ba888d 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,45 @@ export async function GET() {
formattedCountResults[type] = Number(count);
});
- const formattedNotifications = notificationsWithAuthors
- .map(({ notification, author }) => {
- try {
- // all notifications currently require an author
- if (!author) return;
+ // Resolve avatar URLs using ImageUploads service
+ 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.fn(function* () {
+ try {
+ // all notifications currently require an author
+ if (!author) return null;
+
+ const resolvedAvatar = author.avatar
+ ? yield* imageUploads.resolveImageUrl(author.avatar)
+ : 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,
+ },
+ });
+ } catch (error) {
+ console.error("Invalid notification data:", error);
+ return null;
+ }
+ })(),
+ ),
+ );
+ })
+ .pipe(runPromise)
+ .then((results) => results.filter(Boolean));
return NextResponse.json({
notifications: formattedNotifications,
From 1c08e7b8ad5a18bb59eb46fe6fda52568974c1c3 Mon Sep 17 00:00:00 2001
From: ameer2468 <33054370+ameer2468@users.noreply.github.com>
Date: Thu, 23 Oct 2025 18:42:52 +0300
Subject: [PATCH 2/4] Update route.ts
---
apps/web/app/api/notifications/route.ts | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/web/app/api/notifications/route.ts b/apps/web/app/api/notifications/route.ts
index ca36ba888d..079ba17f41 100644
--- a/apps/web/app/api/notifications/route.ts
+++ b/apps/web/app/api/notifications/route.ts
@@ -91,7 +91,6 @@ export async function GET() {
formattedCountResults[type] = Number(count);
});
- // Resolve avatar URLs using ImageUploads service
const formattedNotifications = await Effect.gen(function* () {
const imageUploads = yield* ImageUploads;
From 46dbc3df08345d3514166010015dad3bcadf12f1 Mon Sep 17 00:00:00 2001
From: ameer2468 <33054370+ameer2468@users.noreply.github.com>
Date: Thu, 23 Oct 2025 18:49:33 +0300
Subject: [PATCH 3/4] Update route.ts
---
apps/web/app/api/notifications/route.ts | 50 ++++++++++++-------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/apps/web/app/api/notifications/route.ts b/apps/web/app/api/notifications/route.ts
index 079ba17f41..ac8ec2bdf7 100644
--- a/apps/web/app/api/notifications/route.ts
+++ b/apps/web/app/api/notifications/route.ts
@@ -96,34 +96,34 @@ export async function GET() {
return yield* Effect.all(
notificationsWithAuthors.map(({ notification, author }) =>
- Effect.fn(function* () {
- try {
- // all notifications currently require an author
- if (!author) return null;
+ Effect.gen(function* () {
+ // all notifications currently require an author
+ if (!author) return null;
- const resolvedAvatar = author.avatar
- ? yield* imageUploads.resolveImageUrl(author.avatar)
- : null;
+ const resolvedAvatar = author.avatar
+ ? yield* imageUploads.resolveImageUrl(author.avatar)
+ : 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,
- },
- });
- } catch (error) {
+ 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 null;
- }
- })(),
+ return Effect.succeed(null);
+ }),
+ ),
),
);
})
From 93670a51d022497fcd25060d101afaca746a2c4d Mon Sep 17 00:00:00 2001
From: ameer2468 <33054370+ameer2468@users.noreply.github.com>
Date: Thu, 23 Oct 2025 18:56:44 +0300
Subject: [PATCH 4/4] ts
---
.../dashboard/_components/Notifications/NotificationItem.tsx | 3 ++-
apps/web/app/api/notifications/route.ts | 4 +++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
index 5215423751..90ad061e96 100644
--- a/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
+++ b/apps/web/app/(org)/dashboard/_components/Notifications/NotificationItem.tsx
@@ -1,4 +1,5 @@
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";
@@ -47,7 +48,7 @@ export const NotificationItem = ({
{/* Avatar */}
Effect.succeed(null)))
: null;
return APINotification.parse({