From e150c819cadb5b6932b426fc6a2ec1ceee2d7962 Mon Sep 17 00:00:00 2001 From: Chneemann Date: Fri, 2 Oct 2026 04:14:47 +0200 Subject: [PATCH] refactor(servers): integrate responsive color picker grid into EditServerModal --- .../[serverId]/channels/[channelId]/page.tsx | 2 +- app/api/servers/[serverId]/route.ts | 42 +++++----- components/layout/AppHeader.tsx | 7 +- components/layout/ServerSettingsMenu.tsx | 3 + components/modals/EditServerModal.tsx | 77 ++++++++++++------- 5 files changed, 82 insertions(+), 49 deletions(-) diff --git a/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx b/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx index fb4a543..f77e849 100644 --- a/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx +++ b/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx @@ -48,7 +48,7 @@ export default async function ChannelPage({ } context.params - A promise resolving to the route parameters containing the server ID. - * @returns {Promise} A JSON response containing the updated server object or an error message. - */ +/** Handles PATCH requests to update an existing server's name. */ export async function PATCH( req: Request, { params }: { params: Promise<{ serverId: string }> }, @@ -34,6 +25,7 @@ export async function PATCH( const body = await req.json().catch(() => null); const name = body?.name; + const color = body?.color; // Ensure name is present, valid string type, and not just whitespace if (!name || typeof name !== "string" || !name.trim()) { @@ -53,6 +45,14 @@ export async function PATCH( ); } + // Validate color if provided + if (color !== undefined && (typeof color !== "string" || !color.trim())) { + return NextResponse.json( + { error: "Invalid color value provided." }, + { status: 400 }, + ); + } + // Check if the server exists const [existingServer] = await db .select() @@ -72,10 +72,19 @@ export async function PATCH( ); } + // Prepare fields to update + const updateData: { name: string; color?: string } = { + name: trimmedName, + }; + + if (color && typeof color === "string") { + updateData.color = color.trim(); + } + // Update Server const [updatedServer] = await db .update(servers) - .set({ name: trimmedName }) + .set(updateData) .where(eq(servers.id, serverId)) .returning(); @@ -90,16 +99,7 @@ export async function PATCH( } } -/** - * Handles DELETE requests to remove an existing server. - * - * @async - * @function DELETE - * @param {Request} req - The incoming HTTP request object. - * @param {Object} context - The route context parameters. - * @param {Promise<{ serverId: string }>} context.params - A promise resolving to the route parameters containing the server ID. - * @returns {Promise} A JSON response confirming deletion or returning an error message. - */ +/** Handles DELETE requests to remove an existing server. */ export async function DELETE( req: Request, { params }: { params: Promise<{ serverId: string }> }, diff --git a/components/layout/AppHeader.tsx b/components/layout/AppHeader.tsx index 1b9705e..fbf1f50 100644 --- a/components/layout/AppHeader.tsx +++ b/components/layout/AppHeader.tsx @@ -25,6 +25,7 @@ interface AppHeaderProps { server?: { id: string; name: string; + color: string; }; showFriendsTabs?: boolean; activeTab?: TabType; @@ -140,7 +141,11 @@ export function AppHeader({ {/* Right Action Buttons */}
{server && ( - + )} {showMembersButton && ( diff --git a/components/layout/ServerSettingsMenu.tsx b/components/layout/ServerSettingsMenu.tsx index 8485c63..744bd89 100644 --- a/components/layout/ServerSettingsMenu.tsx +++ b/components/layout/ServerSettingsMenu.tsx @@ -15,12 +15,14 @@ import { CreateChannelModal } from "@/components/modals/CreateChannelModal"; interface ServerSettingsMenuProps { serverId: string; serverName: string; + serverColor: string; } /** Renders a server management dropdown menu with modal triggers for channel, category, and server settings. */ export function ServerSettingsMenu({ serverId, serverName, + serverColor, }: ServerSettingsMenuProps) { const [isMenuOpen, setIsMenuOpen] = useState(false); const [isEditServerOpen, setIsEditServerOpen] = useState(false); @@ -102,6 +104,7 @@ export function ServerSettingsMenu({ isOpen={isEditServerOpen} serverId={serverId} initialName={serverName} + initialColor={serverColor} onClose={() => setIsEditServerOpen(false)} /> void} onClose - Callback function triggered to close the modal. * @property {string} serverId - The unique identifier of the server being edited. * @property {string} initialName - The current name of the server. + * @property {string} [initialColor] - The current accent color of the server. */ interface EditServerModalProps { isOpen: boolean; onClose: () => void; serverId: string; initialName: string; + initialColor: string; } /** * Renders a modal dialog allowing users to modify server properties or delete the server. - * - * @param {EditServerModalProps} props - The component props. - * @param {boolean} props.isOpen - Determines whether the modal dialog is currently visible. - * @param {() => void} props.onClose - Callback function triggered to close the modal. - * @param {string} props.serverId - The unique identifier of the server. - * @param {string} props.initialName - The current name of the server. - * @returns {JSX.Element | null} The rendered edit server modal, or null if closed. */ export function EditServerModal({ isOpen, onClose, serverId, initialName, + initialColor, }: EditServerModalProps) { const [name, setName] = useState(initialName); + const [color, setColor] = useState(initialColor); const [isLoading, setIsLoading] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const [isConfirmingDelete, setIsConfirmingDelete] = useState(false); @@ -52,21 +53,17 @@ export function EditServerModal({ useEffect(() => { setName(initialName); - }, [initialName]); + setColor(initialColor); + }, [initialName, initialColor]); if (!isOpen) return null; - const isChanged = name.trim() !== initialName; + const isChanged = name.trim() !== initialName || color !== initialColor; const isValid = name.trim().length > 0; const canSave = isChanged && isValid && !isLoading && !isDeleting; /** - * Handles the asynchronous update of the server name. - * - * @async - * @function handleUpdate - * @param {React.FormEvent} e - The form submission event. - * @returns {Promise} Resolves when the server update process completes or fails. + * Handles the asynchronous update of the server name and accent color. */ const handleUpdate = async (e: React.FormEvent) => { e.preventDefault(); @@ -79,7 +76,7 @@ export function EditServerModal({ const response = await fetch(`/api/servers/${serverId}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ name: name.trim() }), + body: JSON.stringify({ name: name.trim(), color }), }); if (!response.ok) { @@ -96,11 +93,7 @@ export function EditServerModal({ }; /** - * Handles the asynchronous deletion of the server and redirects the user to the home page. - * - * @async - * @function handleDelete - * @returns {Promise} Resolves when the server deletion process completes or fails. + * Handles the asynchronous deletion of the server. */ const handleDelete = async () => { if (!isConfirmingDelete) { @@ -154,7 +147,7 @@ export function EditServerModal({ Change server details or delete this server.

-
+
+
+
+ +
+ +
+ {SERVER_COLOR_OPTIONS.map((c) => { + const isSelected = color === c; + return ( + + ); + })} +
+
+ {error &&

{error}

} -
+
- {isConfirmingDelete ? "Sure?" : "Delete Server "} + {isConfirmingDelete ? "Sure?" : "Delete Server"}