From 7043487fc2bd0578a8dfe6a734b93caa3cdba167 Mon Sep 17 00:00:00 2001 From: echo Date: Wed, 18 Mar 2026 12:37:21 +0100 Subject: [PATCH] edit local user fix --- apps/admin/data/fitai.db | Bin 172032 -> 172032 bytes apps/admin/src/app/api/users/route.ts | 55 ++++++++++-------- .../src/components/users/CreateUserModal.tsx | 2 + apps/admin/src/hooks/use-api.ts | 2 +- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db index 4ffef65d999751f4a8ba4e5ef52ae0125016fd71..38a0ab370f71f9b4499a4ef0c8acc5a103cac793 100644 GIT binary patch delta 416 zcmZoTz}0YoYl1Xm+e8^>#lKNYsqtOv!cK$p6Ez6URPOB zQ3hT~7FJybhLY6Wf_Ou7b7Ko*V*_Jz19Ri}%<`(t3`0wks)7QCf&#td)Vz|+UERKna~XE6$;l`+E;BHxD$Xg+GEFVY%bjc~`zk65Y`8edh9{=vX6C`n zt~!fuHqg?^wQ|Q9T_?NBJMvdB@%q{-%JV`!G1*t%bMiZRUU{IizAZu5%EiFIz{ao6 zz^}fULqV2bQGwZ&5udl&CVS}b;bG&?VBp`%e~y1Df5v7$g9v_J9%flaSdg$am)f_N w+B0r1wP)&g5Mbkf%)tML|2zLD{ov%EHXR$hQ4OKa+$20RByYnE(I) delta 205 zcmZoTz}0YoYl1Xm(?l6(#-@!4OZfR%c`cdwYWb(}J>lKNYq?obL7jK9rR*!tSbb@E zUS35OmdOX_DokD@rzlXw$m$_22@Eu=0B_Z01ss<)64fd3tU=BiH00{Y_k~{G|;1TlvrN zPu(nF5Wzn&fWNuazP;3*aeJvfQ@;ZrEB^}y{y+TR`9JZ$<$tkRFyI>h_80w35&{5l C6gvq3 diff --git a/apps/admin/src/app/api/users/route.ts b/apps/admin/src/app/api/users/route.ts index 832b00d..f5e9f54 100644 --- a/apps/admin/src/app/api/users/route.ts +++ b/apps/admin/src/app/api/users/route.ts @@ -387,24 +387,27 @@ export async function PUT(request: NextRequest) { // Update Clerk publicMetadata (role/gymId) to propagate via webhook // Note: Only update metadata when a change is requested - try { - const client = await clerkClient(); - const publicMetadata: Record = {}; - log.debug("Preparing Clerk metadata update", { - targetUserId: id, - role, - gymId, - }); + const client = await clerkClient(); + const publicMetadata: Record = {}; + log.debug("Preparing Clerk metadata update", { + targetUserId: id, + role, + gymId, + }); - if (role) { - publicMetadata.role = role; - } - if (gymId !== undefined) { - publicMetadata.gymId = gymId === null ? null : String(gymId); - } + if (role) { + publicMetadata.role = role; + } + if (gymId !== undefined) { + publicMetadata.gymId = gymId === null ? null : String(gymId); + } + + if (Object.keys(publicMetadata).length > 0) { + log.debug("Updating Clerk user metadata", { publicMetadata }); + try { + // Check if user exists in Clerk first + await client.users.getUser(id); - if (Object.keys(publicMetadata).length > 0) { - log.debug("Updating Clerk user metadata", { publicMetadata }); const clerkResult = await client.users.updateUser(id, { publicMetadata, }); @@ -413,14 +416,20 @@ export async function PUT(request: NextRequest) { role: clerkResult.publicMetadata?.role, gymId: clerkResult.publicMetadata?.gymId, }); - } else { - log.debug("No Clerk metadata changes requested"); + } catch (clerkErr: any) { + // User might not exist in Clerk yet - that's OK for local users + if ( + clerkErr?.status === 404 || + clerkErr?.errors?.[0]?.code === "resource_not_found" + ) { + log.debug( + "User not found in Clerk, skipping metadata update (local-only user)", + ); + } else { + log.error("Clerk metadata update failed", clerkErr, { userId: id }); + // Don't fail the whole request - local DB update can still proceed + } } - } catch (clerkErr: any) { - log.error("Clerk metadata update failed", clerkErr, { userId: id }); - return internalErrorResponse( - "Failed to update role/gym in identity provider", - ); } // Update local DB for immediate UI feedback (webhook will also sync) diff --git a/apps/admin/src/components/users/CreateUserModal.tsx b/apps/admin/src/components/users/CreateUserModal.tsx index 8bab871..20eeba5 100644 --- a/apps/admin/src/components/users/CreateUserModal.tsx +++ b/apps/admin/src/components/users/CreateUserModal.tsx @@ -26,6 +26,7 @@ import { type InvitationOptionsData, } from "@/lib/validation/user-schemas"; import { ChevronLeft, ChevronRight, Check } from "lucide-react"; +import { useGyms } from "@/hooks/use-api"; interface CreateUserModalProps { open: boolean; @@ -45,6 +46,7 @@ export function CreateUserModal({ const [basicInfo, setBasicInfo] = useState(null); const [clientInfo, setClientInfo] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); + const { data: gyms = [] } = useGyms(); // Step 1: Role Selection Form const roleForm = useForm({ diff --git a/apps/admin/src/hooks/use-api.ts b/apps/admin/src/hooks/use-api.ts index 287eab0..3cead9c 100644 --- a/apps/admin/src/hooks/use-api.ts +++ b/apps/admin/src/hooks/use-api.ts @@ -170,7 +170,7 @@ export function useGyms() { queryKey: ["gyms"], queryFn: () => fetchApi<{ data: { gyms: Gym[] } }>("/api/gyms").then( - (res) => res.data?.gyms ?? [], + (res) => res.data?.gyms ?? (Array.isArray(res) ? res : []), ), }); }