From 3a5cd132fc13b0bdc933d4bdd539260f4d46f584 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Tue, 31 Mar 2026 13:06:46 +0530 Subject: [PATCH 1/3] fix: profile cover update --- .../profile/content/pages/general/form.tsx | 16 ++--- apps/web/helpers/cover-image.helper.ts | 61 +++++++------------ 2 files changed, 29 insertions(+), 48 deletions(-) diff --git a/apps/web/core/components/settings/profile/content/pages/general/form.tsx b/apps/web/core/components/settings/profile/content/pages/general/form.tsx index 778e2024de8..bfecce3f66d 100644 --- a/apps/web/core/components/settings/profile/content/pages/general/form.tsx +++ b/apps/web/core/components/settings/profile/content/pages/general/form.tsx @@ -151,12 +151,13 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin }; const updateCurrentUserDetail = updateCurrentUser(userPayload).finally(() => setIsLoading(false)); - const updateCurrentUserProfile = updateUserProfile(profilePayload).finally(() => setIsLoading(false)); - - const promises = [updateCurrentUserDetail, updateCurrentUserProfile]; - const updateUserAndProfile = Promise.all(promises); + const promises: Promise[] = [updateCurrentUserDetail]; + if (profilePayload.role !== profile.role) { + const updateCurrentUserProfile = updateUserProfile(profilePayload).finally(() => setIsLoading(false)); + promises.push(updateCurrentUserProfile); + } - setPromiseToast(updateUserAndProfile, { + setPromiseToast(Promise.allSettled(promises), { loading: "Updating...", success: { title: "Success!", @@ -167,11 +168,6 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin message: () => `There was some error in updating your profile. Please try again.`, }, }); - updateUserAndProfile - .then(() => { - return; - }) - .catch(() => {}); }; return ( diff --git a/apps/web/helpers/cover-image.helper.ts b/apps/web/helpers/cover-image.helper.ts index caac9df416f..cfabcaacbb2 100644 --- a/apps/web/helpers/cover-image.helper.ts +++ b/apps/web/helpers/cover-image.helper.ts @@ -84,7 +84,7 @@ export const DEFAULT_COVER_IMAGE_URL = STATIC_COVER_IMAGES.IMAGE_1; */ const STATIC_COVER_IMAGES_SET = new Set(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,9 @@ 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 + if (imageUrl.includes("unsplash.com")) return "unsplash"; + if (imageUrl.startsWith("http")) return "uploaded_asset"; return "uploaded_asset"; @@ -136,7 +139,7 @@ export function getCoverImageDisplayURL( const imageType = getCoverImageType(imageUrl); - if (imageType === "local_static") { + if (imageType === "local_static" || imageType === "unsplash") { return imageUrl; } @@ -149,6 +152,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 +168,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 +213,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 +245,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 +255,20 @@ export const handleCoverImageChange = async ( entityType: EFileAssetType; isUserAsset?: boolean; } -): Promise => { +): Promise => { 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; }; /** From 5ee3040533fbf8e7ead09e51499afd781a36ccee Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Tue, 31 Mar 2026 15:28:51 +0530 Subject: [PATCH 2/3] chore: code refactoring --- .../profile/content/pages/general/form.tsx | 18 +++++++++++++++--- apps/web/helpers/cover-image.helper.ts | 12 ++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/web/core/components/settings/profile/content/pages/general/form.tsx b/apps/web/core/components/settings/profile/content/pages/general/form.tsx index bfecce3f66d..c79b876a65c 100644 --- a/apps/web/core/components/settings/profile/content/pages/general/form.tsx +++ b/apps/web/core/components/settings/profile/content/pages/general/form.tsx @@ -150,14 +150,26 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin role: formData.role, }; - const updateCurrentUserDetail = updateCurrentUser(userPayload).finally(() => setIsLoading(false)); + const updateCurrentUserDetail = updateCurrentUser(userPayload); const promises: Promise[] = [updateCurrentUserDetail]; if (profilePayload.role !== profile.role) { - const updateCurrentUserProfile = updateUserProfile(profilePayload).finally(() => setIsLoading(false)); + const updateCurrentUserProfile = updateUserProfile(profilePayload); promises.push(updateCurrentUserProfile); } - setPromiseToast(Promise.allSettled(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"); + } + return results.map((result) => (result as PromiseFulfilledResult).value); + }); + + updatePromise.finally(() => setIsLoading(false)); + + setPromiseToast(updatePromise, { loading: "Updating...", success: { title: "Success!", diff --git a/apps/web/helpers/cover-image.helper.ts b/apps/web/helpers/cover-image.helper.ts index cfabcaacbb2..bfcecfcedf5 100644 --- a/apps/web/helpers/cover-image.helper.ts +++ b/apps/web/helpers/cover-image.helper.ts @@ -114,8 +114,16 @@ 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 - if (imageUrl.includes("unsplash.com")) return "unsplash"; + // 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"; From 3c9642bd810289d394135374374b44f5ec6b1a61 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Tue, 31 Mar 2026 15:47:13 +0530 Subject: [PATCH 3/3] chore: code refactoring --- .../profile/content/pages/general/form.tsx | 28 +++++++++++-------- apps/web/helpers/cover-image.helper.ts | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/web/core/components/settings/profile/content/pages/general/form.tsx b/apps/web/core/components/settings/profile/content/pages/general/form.tsx index c79b876a65c..e20245f8352 100644 --- a/apps/web/core/components/settings/profile/content/pages/general/form.tsx +++ b/apps/web/core/components/settings/profile/content/pages/general/form.tsx @@ -157,17 +157,23 @@ export const GeneralProfileSettingsForm = observer(function GeneralProfileSettin promises.push(updateCurrentUserProfile); } - 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"); - } - return results.map((result) => (result as PromiseFulfilledResult).value); - }); - - updatePromise.finally(() => setIsLoading(false)); + 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).value + ); + if (values.some((v) => v === undefined)) { + throw new Error("Failed to update profile"); + } + return values; + }) + .finally(() => setIsLoading(false)); setPromiseToast(updatePromise, { loading: "Updating...", diff --git a/apps/web/helpers/cover-image.helper.ts b/apps/web/helpers/cover-image.helper.ts index bfcecfcedf5..6ef7b2854c5 100644 --- a/apps/web/helpers/cover-image.helper.ts +++ b/apps/web/helpers/cover-image.helper.ts @@ -276,7 +276,7 @@ export const handleCoverImageChange = async ( return; } - return; + return { cover_image: newImage }; }; /**