From 314c363e5ca69a50626650ade8968feec583e5ce Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Wed, 24 Dec 2025 12:18:08 +0200
Subject: feat: add support for user avatars (#2296)

* feat: add support for user avatars

* more fixes

* more fixes

* more fixes

* more fixes
---
 .../components/dashboard/header/ProfileOptions.tsx | 23 +++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

(limited to 'apps/web/components/dashboard/header/ProfileOptions.tsx')

diff --git a/apps/web/components/dashboard/header/ProfileOptions.tsx b/apps/web/components/dashboard/header/ProfileOptions.tsx
index 7ccc0078..5199bdec 100644
--- a/apps/web/components/dashboard/header/ProfileOptions.tsx
+++ b/apps/web/components/dashboard/header/ProfileOptions.tsx
@@ -1,5 +1,6 @@
 "use client";
 
+import { useMemo } from "react";
 import Link from "next/link";
 import { redirect, useRouter } from "next/navigation";
 import { useToggleTheme } from "@/components/theme-provider";
@@ -11,11 +12,14 @@ import {
   DropdownMenuTrigger,
 } from "@/components/ui/dropdown-menu";
 import { Separator } from "@/components/ui/separator";
+import { UserAvatar } from "@/components/ui/user-avatar";
 import { useTranslation } from "@/lib/i18n/client";
 import { LogOut, Moon, Paintbrush, Settings, Shield, Sun } from "lucide-react";
 import { useSession } from "next-auth/react";
 import { useTheme } from "next-themes";
 
+import { useWhoAmI } from "@karakeep/shared-react/hooks/users";
+
 import { AdminNoticeBadge } from "../../admin/AdminNotices";
 
 function DarkModeToggle() {
@@ -43,7 +47,12 @@ export default function SidebarProfileOptions() {
   const { t } = useTranslation();
   const toggleTheme = useToggleTheme();
   const { data: session } = useSession();
+  const { data: whoami } = useWhoAmI();
   const router = useRouter();
+
+  const avatarImage = whoami?.image ?? null;
+  const avatarUrl = useMemo(() => avatarImage ?? null, [avatarImage]);
+
   if (!session) return redirect("/");
 
   return (
@@ -53,13 +62,21 @@ export default function SidebarProfileOptions() {
           className="border-new-gray-200 aspect-square rounded-full border-4 bg-black p-0 text-white"
           variant="ghost"
         >
-          {session.user.name?.charAt(0) ?? "U"}
+          <UserAvatar
+            image={avatarUrl}
+            name={session.user.name}
+            className="h-full w-full rounded-full"
+          />
         </Button>
       </DropdownMenuTrigger>
       <DropdownMenuContent className="mr-2 min-w-64 p-2">
         <div className="flex gap-2">
-          <div className="border-new-gray-200 flex aspect-square size-11 items-center justify-center rounded-full border-4 bg-black p-0 text-white">
-            {session.user.name?.charAt(0) ?? "U"}
+          <div className="border-new-gray-200 flex aspect-square size-11 items-center justify-center overflow-hidden rounded-full border-4 bg-black p-0 text-white">
+            <UserAvatar
+              image={avatarUrl}
+              name={session.user.name}
+              className="h-full w-full"
+            />
           </div>
           <div className="flex flex-col">
             <p>{session.user.name}</p>
-- 
cgit v1.2.3-70-g09d2

