[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:
parent
9fa707b260
commit
d8ed19f204
2 changed files with 55 additions and 48 deletions
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue