[WEB-6794] fix: align profile cover update with correct unsplash and upload handling (#8830)

* fix: profile cover update

* chore: code refactoring

* chore: code refactoring
This commit is contained in:
Anmol Singh Bhatia 2026-03-31 15:54:12 +05:30 committed by GitHub
parent 9fa707b260
commit d8ed19f204
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 48 deletions

View file

@ -150,13 +150,32 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
role: formData.role,
};
const updateCurrentUserDetail = updateCurrentUser(userPayload).finally(() => setIsLoading(false));
const updateCurrentUserProfile = updateUserProfile(profilePayload).finally(() => setIsLoading(false));
const updateCurrentUserDetail = updateCurrentUser(userPayload);
const promises: Promise<IUser | TUserProfile | undefined>[] = [updateCurrentUserDetail];
if (profilePayload.role !== profile.role) {
const updateCurrentUserProfile = updateUserProfile(profilePayload);
promises.push(updateCurrentUserProfile);
}
const promises = [updateCurrentUserDetail, updateCurrentUserProfile];
const updateUserAndProfile = Promise.all(promises);
const updatePromise = Promise.allSettled(promises)
.then((results) => {
const rejectedResult = results.find((result) => result.status === "rejected") as
| PromiseRejectedResult
| undefined;
if (rejectedResult) {
throw rejectedResult.reason ?? new Error("Failed to update profile");
}
const values = results.map(
(result) => (result as PromiseFulfilledResult<IUser | TUserProfile | undefined>).value
);
if (values.some((v) => v === undefined)) {
throw new Error("Failed to update profile");
}
return values;
})
.finally(() => setIsLoading(false));
setPromiseToast(updateUserAndProfile, {
setPromiseToast(updatePromise, {
loading: "Updating...",
success: {
title: "Success!",
@ -167,11 +186,6 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin
message: () => `There was some error in updating your profile. Please try again.`,
},
});
updateUserAndProfile
.then(() => {
return;
})
.catch(() => {});
};
return (

View file

@ -84,7 +84,7 @@ export const DEFAULT_COVER_IMAGE_URL = STATIC_COVER_IMAGES.IMAGE_1;
*/
const STATIC_COVER_IMAGES_SET = new Set<string>(Object.values(STATIC_COVER_IMAGES));
export type TCoverImageType = "local_static" | "uploaded_asset";
export type TCoverImageType = "local_static" | "uploaded_asset" | "unsplash";
export type TCoverImageResult = {
needsUpload: boolean;
@ -114,6 +114,17 @@ export const getCoverImageType = (imageUrl: string): TCoverImageType => {
// Check against the explicit set of static images
if (isStaticCoverImage(imageUrl)) return "local_static";
// Check if it's an Unsplash image by validating the hostname
try {
const url = new URL(imageUrl);
const hostname = url.hostname.toLowerCase();
if (hostname === "unsplash.com" || hostname.endsWith(".unsplash.com")) {
return "unsplash";
}
} catch {
// If URL parsing fails (e.g., relative path), fall through to other checks
}
if (imageUrl.startsWith("http")) return "uploaded_asset";
return "uploaded_asset";
@ -136,7 +147,7 @@ export function getCoverImageDisplayURL(
const imageType = getCoverImageType(imageUrl);
if (imageType === "local_static") {
if (imageType === "local_static" || imageType === "unsplash") {
return imageUrl;
}
@ -149,6 +160,7 @@ export function getCoverImageDisplayURL(
/**
* Analyzes cover image change and determines what action to take
* Merged with isUnsplashImage logic - now detects unsplash images as a separate type
*/
export const analyzeCoverImageChange = (
currentImage: string | null | undefined,
@ -164,10 +176,18 @@ export const analyzeCoverImageChange = (
};
}
const imageType = getCoverImageType(newImage ?? "");
if (!newImage) {
return {
needsUpload: false,
imageType: "uploaded_asset",
shouldUpdate: true,
};
}
const imageType = getCoverImageType(newImage);
return {
needsUpload: imageType === "local_static",
needsUpload: imageType === "local_static" || imageType === "unsplash",
imageType,
shouldUpdate: hasChanged,
};
@ -201,7 +221,7 @@ export const uploadCoverImage = async (
throw new Error("Invalid file type. Please select an image.");
}
const fileName = imageUrl.split("/").pop() || "cover.jpg";
const fileName = imageUrl.split("/").pop()?.split("?")[0] || "image.jpg";
const file = new File([blob], fileName, { type: blob.type });
// Upload based on context
@ -233,7 +253,6 @@ export const uploadCoverImage = async (
/**
* Main utility to handle cover image changes with upload
* Returns the payload fields that should be updated
*/
export const handleCoverImageChange = async (
currentImage: string | null | undefined,
@ -244,46 +263,20 @@ export const handleCoverImageChange = async (
entityType: EFileAssetType;
isUserAsset?: boolean;
}
): Promise<TCoverImagePayload | null> => {
): Promise<TCoverImagePayload | undefined> => {
const analysis = analyzeCoverImageChange(currentImage, newImage);
if (!analysis.shouldUpdate) return;
// No change detected
if (!analysis.shouldUpdate) {
return null;
}
// Image removed
if (!newImage) {
return {
cover_image: null,
cover_image_url: null,
cover_image_asset: null,
};
return { cover_image: null, cover_image_url: null, cover_image_asset: null };
}
// Local static image - needs upload
if (analysis.needsUpload) {
const uploadedUrl = await uploadCoverImage(newImage, uploadConfig);
// For BOTH user assets AND project assets:
// The backend auto-links when entity_identifier is set correctly
// For project assets: auto-linked server-side, no payload needed
// For user assets: return URL for immediate UI feedback
if (uploadConfig.isUserAsset) {
return {
cover_image: uploadedUrl,
};
} else {
return null;
}
await uploadCoverImage(newImage, uploadConfig);
return;
}
// External/uploaded asset (e.g., Unsplash URL, pre-uploaded asset)
// Return the URL to be saved in the backend
return {
cover_image: newImage,
};
return { cover_image: newImage };
};
/**