From 256c3d03e34d2084c69e1ae7fcfde072501675db Mon Sep 17 00:00:00 2001 From: Chneemann Date: Wed, 23 Sep 2026 10:32:44 +0200 Subject: [PATCH] refactor(settings): sync status and color updates directly via UserContext --- app/(app)/layout.tsx | 1 - components/layout/AppSidebar.tsx | 21 ++------ components/settings/SettingsView.tsx | 79 ++++++++-------------------- components/sidebar/UserPanel.tsx | 37 ++++--------- lib/context/ServerContext.tsx | 32 +++++++++-- lib/context/UserContext.tsx | 16 ++++-- 6 files changed, 78 insertions(+), 108 deletions(-) diff --git a/app/(app)/layout.tsx b/app/(app)/layout.tsx index b770043..a5630a9 100644 --- a/app/(app)/layout.tsx +++ b/app/(app)/layout.tsx @@ -76,7 +76,6 @@ export default async function AppLayout({
{children}
diff --git a/components/layout/AppSidebar.tsx b/components/layout/AppSidebar.tsx index e21a93a..2c06e7a 100644 --- a/components/layout/AppSidebar.tsx +++ b/components/layout/AppSidebar.tsx @@ -13,7 +13,6 @@ import { useActiveServer, type ServerWithChannels, } from "@/lib/context/ServerContext"; -import type { UserStatus } from "@/db/schema"; import { clsx } from "clsx"; import { DirectMessageSidebar, @@ -21,26 +20,14 @@ import { } from "../sidebar/DirectMessageSidebar"; import { usePathname } from "next/navigation"; -/** Properties representing the user in the sidebar. */ -export interface SidebarUser { - username: string; - color: string; - status: UserStatus; -} - /** Properties for the AppSidebar component. */ interface AppSidebarProps { servers: ServerWithChannels[]; conversations: SidebarConversation[]; - user: SidebarUser; } -/**Renders the responsive application sidebar containing server navigation, channel lists, and user profile. */ -export function AppSidebar({ - servers, - user, - conversations = [], -}: AppSidebarProps) { +/** Renders the responsive application sidebar containing server navigation, channel lists, and user profile. */ +export function AppSidebar({ servers, conversations = [] }: AppSidebarProps) { const { isNavOpen, closeAll } = useSidebarStore(); const { activeServer } = useActiveServer(); const pathname = usePathname(); @@ -66,7 +53,7 @@ export function AppSidebar({ )}
- +
@@ -92,7 +79,7 @@ export function AppSidebar({ )} - + ); diff --git a/components/settings/SettingsView.tsx b/components/settings/SettingsView.tsx index 34847e8..e27b6b1 100644 --- a/components/settings/SettingsView.tsx +++ b/components/settings/SettingsView.tsx @@ -1,33 +1,22 @@ /** * @file components/settings/SettingsView.tsx - * @description Main settings container component for managing user profile and preferences. + * @description Settings view component for updating user profile attributes like online status and avatar color. */ "use client"; -import { useState } from "react"; import { UserAvatar } from "@/components/ui/UserAvatar"; -import { UserStatus, User } from "@/db/schema"; +import { UserStatus } from "@/db/schema"; import { MEMBER_STATUS_COLOR_CLASSES, MEMBER_COLOR_OPTIONS, } from "@/lib/constants/member.styles"; import { UserRound, Palette } from "lucide-react"; +import { useUser } from "@/lib/context/UserContext"; -/** Props for the SettingsView component. */ -interface SettingsViewProps { - userId: string; - currentUser: User; -} - -/** Renders the user settings view for profile management, status selection, and avatar color customization. */ -export function SettingsView({ userId, currentUser }: SettingsViewProps) { - const [selectedStatus, setSelectedStatus] = useState( - currentUser.status, - ); - const [selectedColor, setSelectedColor] = useState( - currentUser.color || MEMBER_COLOR_OPTIONS[0], - ); +/** Renders the user settings view allowing profile, online status, and color customizations. */ +export function SettingsView() { + const { currentUser, updateCurrentUser } = useUser(); const statuses: { label: string; value: UserStatus }[] = [ { label: "Online", value: "ONLINE" }, @@ -36,42 +25,18 @@ export function SettingsView({ userId, currentUser }: SettingsViewProps) { { label: "DND", value: "DND" }, ]; - /** Updates local status state on user selection. */ - const handleStatusChange = async (newStatus: UserStatus) => { - setSelectedStatus(newStatus); - try { - await fetch("/api/users/profile", { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ status: newStatus }), - }); - } catch (err) { - console.error("Failed to update status", err); - } - }; - - /** Updates local avatar color state on user selection. */ - const handleColorChange = async (newColor: string) => { - setSelectedColor(newColor); - try { - await fetch("/api/users/profile", { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ color: newColor }), - }); - } catch (err) { - console.error("Failed to update color", err); - } + /** Sends optimistic updates to context and persists profile changes to the server API. */ + const updateProfile = (fields: Partial) => { + updateCurrentUser(fields); + fetch("/api/users/profile", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(fields), + }).catch((err) => console.error("Failed to update profile", err)); }; if (!currentUser) return null; - const userWithUpdatedSettings = { - ...currentUser, - status: selectedStatus, - color: selectedColor, - }; - return (
{/* Header */} @@ -85,7 +50,7 @@ export function SettingsView({ userId, currentUser }: SettingsViewProps) { {/* Profile Overview Card */}
- +

{currentUser.username} @@ -101,14 +66,12 @@ export function SettingsView({ userId, currentUser }: SettingsViewProps) {

{statuses.map((status) => { - const isSelected = selectedStatus === status.value; - const statusBgColor = MEMBER_STATUS_COLOR_CLASSES[status.value]; - + const isSelected = currentUser.status === status.value; return ( @@ -132,12 +97,12 @@ export function SettingsView({ userId, currentUser }: SettingsViewProps) {
{MEMBER_COLOR_OPTIONS.map((colorClass) => { - const isSelected = selectedColor === colorClass; + const isSelected = currentUser.color === colorClass; return (