mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
A profile PUT/PATCH validated as one safeParse and wrote as one transaction, so a single rejected field took every sibling change down with it - editing height and gender together lost both, and onboarding lost a whole baseline step to one field. The schema has no cross-field dependency, so applyProfileUpdate now re-validates each present field against its own schema and writes whatever validates; only a body where nothing validates is refused outright, naming the field that blocked it. The top-level error string also stopped being a raw Zod message (issues[0].message) that could read "Invalid option: expected one of "MALE"|"FEMALE"|"OTHER"" on a person's screen. It's now a person-safe sentence plus a stable errorCode for the web client to localize; the full per-field detail is relocated (not deleted) into details.issues, matching the multi-issue envelope the iOS contract already expects from other write routes.
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import {
|
|
apiSuccess,
|
|
apiError,
|
|
apiValidationError,
|
|
getClientIp,
|
|
safeJson,
|
|
} from "@/lib/api-response";
|
|
import { NextRequest } from "next/server";
|
|
import { apiHandler, requireAuth } from "@/lib/api-handler";
|
|
import { annotate } from "@/lib/logging/context";
|
|
import { applyProfileUpdate } from "@/lib/auth/profile-update";
|
|
|
|
export const PUT = apiHandler(async (request: NextRequest) => {
|
|
const { user } = await requireAuth();
|
|
|
|
const { data: body, error: jsonError } = await safeJson(request, {
|
|
maxBytes: 64 * 1024,
|
|
});
|
|
if (jsonError) return jsonError;
|
|
|
|
const result = await applyProfileUpdate(user.id, body, getClientIp(request));
|
|
if (!result.ok) {
|
|
return result.issues
|
|
? apiValidationError(
|
|
result.message,
|
|
result.issues,
|
|
result.status,
|
|
result.errorCode ? { errorCode: result.errorCode } : undefined,
|
|
)
|
|
: apiError(result.message, result.status);
|
|
}
|
|
|
|
annotate({ action: { name: "auth.profile.update" } });
|
|
|
|
return apiSuccess({
|
|
id: result.user.id,
|
|
username: result.user.username,
|
|
email: result.user.email,
|
|
role: result.user.role,
|
|
heightCm: result.user.heightCm,
|
|
dateOfBirth: result.user.dateOfBirth,
|
|
gender: result.user.gender,
|
|
timezone: result.user.timezone,
|
|
fullName: result.user.fullName,
|
|
insurerName: result.user.insurerName,
|
|
insurerIkNumber: result.user.insurerIkNumber,
|
|
hasInsuranceNumber: result.user.hasInsuranceNumber,
|
|
...(result.rejectedFields ? { rejectedFields: result.rejectedFields } : {}),
|
|
});
|
|
});
|