Merged in fix/update-only-dirty-fields-profile (pull request #481)
fix: only send updated fields to API Approved-by: Michael Zetterberg
This commit is contained in:
@@ -4,10 +4,12 @@ import { z } from "zod"
|
||||
|
||||
import { ApiLang } from "@/constants/languages"
|
||||
import * as api from "@/lib/api"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import { protectedServerActionProcedure } from "@/server/trpc"
|
||||
|
||||
import { editProfileSchema } from "@/components/Forms/Edit/Profile/schema"
|
||||
import { countriesMap } from "@/components/TempDesignSystem/Form/Country/countries"
|
||||
import { getIntl } from "@/i18n"
|
||||
import { phoneValidator } from "@/utils/phoneValidator"
|
||||
|
||||
import { Status } from "@/types/components/myPages/myProfile/edit"
|
||||
@@ -32,69 +34,176 @@ const editProfilePayload = z
|
||||
delete data.password
|
||||
delete data.newPassword
|
||||
}
|
||||
if (data.phoneNumber) {
|
||||
data.phoneNumber = data.phoneNumber.replaceAll(" ", "").trim()
|
||||
}
|
||||
return data
|
||||
})
|
||||
|
||||
export const editProfile = protectedServerActionProcedure
|
||||
.input(editProfileSchema)
|
||||
.mutation(async function ({ ctx, input }) {
|
||||
const intl = await getIntl()
|
||||
const payload = editProfilePayload.safeParse(input)
|
||||
if (!payload.success) {
|
||||
console.error(
|
||||
"editProfile payload validation error",
|
||||
JSON.stringify({
|
||||
query: input,
|
||||
error: payload.error,
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
data: input,
|
||||
issues: payload.error.issues.map((issue) => ({
|
||||
field: issue.path.join("."),
|
||||
message: issue.message,
|
||||
})),
|
||||
message: "Validation failed.",
|
||||
message: intl.formatMessage({
|
||||
id: "An error occured when trying to update profile.",
|
||||
}),
|
||||
status: Status.error,
|
||||
}
|
||||
}
|
||||
|
||||
const response = await api.patch(api.endpoints.v1.profile, {
|
||||
body: payload.data,
|
||||
const profile = await serverClient().user.get({ mask: false })
|
||||
if (!profile || "error" in profile) {
|
||||
console.error(
|
||||
"editProfile profile fetch error",
|
||||
JSON.stringify({
|
||||
query: input,
|
||||
error: profile?.error,
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
data: input,
|
||||
issues: [],
|
||||
message: intl.formatMessage({
|
||||
id: "An error occured when trying to update profile.",
|
||||
}),
|
||||
status: Status.error,
|
||||
}
|
||||
}
|
||||
|
||||
const body: Partial<z.infer<typeof editProfilePayload>> = {}
|
||||
Object.keys(payload.data).forEach((key) => {
|
||||
const typedKey = key as unknown as keyof z.infer<
|
||||
typeof editProfilePayload
|
||||
>
|
||||
if (typedKey === "password" || typedKey === "newPassword") {
|
||||
body[typedKey] = payload.data[typedKey]
|
||||
return
|
||||
}
|
||||
|
||||
if (typedKey === "address") {
|
||||
if (
|
||||
(payload.data.address.city === profile.address.city ||
|
||||
(!payload.data.address.city && !profile.address.city)) &&
|
||||
(payload.data.address.countryCode === profile.address.countryCode ||
|
||||
(!payload.data.address.countryCode &&
|
||||
!profile.address.countryCode)) &&
|
||||
(payload.data.address.streetAddress ===
|
||||
profile.address.streetAddress ||
|
||||
(!payload.data.address.streetAddress &&
|
||||
!profile.address.streetAddress)) &&
|
||||
(payload.data.address.zipCode === profile.address.zipCode ||
|
||||
(!payload.data.address.zipCode && !profile.address.zipCode))
|
||||
) {
|
||||
// untouched - noop
|
||||
} else {
|
||||
/** API clears all other fields not sent in address payload */
|
||||
body.address = payload.data.address
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (payload.data[typedKey] !== profile[typedKey]) {
|
||||
// @ts-ignore
|
||||
body[typedKey] = payload.data[typedKey]
|
||||
}
|
||||
})
|
||||
|
||||
if (Object.keys(body).length === 0) {
|
||||
return {
|
||||
data: input,
|
||||
message: intl.formatMessage({ id: "Successfully updated profile!" }),
|
||||
status: Status.success,
|
||||
}
|
||||
}
|
||||
|
||||
const apiResponse = await api.patch(api.endpoints.v1.profile, {
|
||||
body,
|
||||
cache: "no-store",
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||
},
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
console.info(`Response not ok`)
|
||||
console.error(response)
|
||||
if (!apiResponse.ok) {
|
||||
const text = await apiResponse.text()
|
||||
console.error(
|
||||
"editProfile api patch error",
|
||||
JSON.stringify({
|
||||
query: input,
|
||||
error: {
|
||||
status: apiResponse.status,
|
||||
statusText: apiResponse.statusText,
|
||||
error: text,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
data: input,
|
||||
issues: [],
|
||||
message: "Server error",
|
||||
message: intl.formatMessage({
|
||||
id: "An error occured when trying to update profile.",
|
||||
}),
|
||||
status: Status.error,
|
||||
}
|
||||
}
|
||||
|
||||
const json = await response.json()
|
||||
const json = await apiResponse.json()
|
||||
if (json.errors?.length) {
|
||||
json.errors.forEach((error: any) => {
|
||||
console.info(`API Fail in response`)
|
||||
console.error(error)
|
||||
console.warn(
|
||||
"editProfile api patch errors (not aborting)",
|
||||
JSON.stringify({
|
||||
query: input,
|
||||
error,
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const validatedData = editProfileSchema.safeParse(json.data.attributes)
|
||||
if (!validatedData.success) {
|
||||
console.log({ ees: validatedData.error })
|
||||
console.error(
|
||||
"editProfile validation error",
|
||||
JSON.stringify({
|
||||
query: input,
|
||||
error: validatedData.error,
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
data: input,
|
||||
issues: validatedData.error.issues.map((issue) => ({
|
||||
field: issue.path.join("."),
|
||||
message: issue.message,
|
||||
})),
|
||||
message: "Data is insufficient",
|
||||
message: intl.formatMessage({
|
||||
id: "An error occured when trying to update profile.",
|
||||
}),
|
||||
status: Status.error,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: validatedData.data,
|
||||
message: "All good!",
|
||||
message: intl.formatMessage({ id: "Successfully updated profile!" }),
|
||||
status: Status.success,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -82,16 +82,10 @@ export default function Form({ user }: EditFormProps) {
|
||||
console.error(issue)
|
||||
})
|
||||
}
|
||||
toast.error(
|
||||
intl.formatMessage({
|
||||
id: "An error occured when trying to update profile.",
|
||||
})
|
||||
)
|
||||
toast.error(response.message)
|
||||
break
|
||||
case Status.success:
|
||||
toast.success(
|
||||
intl.formatMessage({ id: "Successfully updated profile!" })
|
||||
)
|
||||
toast.success(response.message)
|
||||
utils.user.get.invalidate()
|
||||
router.push(profile[lang])
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user