Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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!",
Expand All @@ -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 (
Expand Down
69 changes: 31 additions & 38 deletions apps/web/helpers/cover-image.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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";
Expand All @@ -136,7 +147,7 @@ export function getCoverImageDisplayURL(

const imageType = getCoverImageType(imageUrl);

if (imageType === "local_static") {
if (imageType === "local_static" || imageType === "unsplash") {
return imageUrl;
}

Expand All @@ -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,
Expand All @@ -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,
};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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 };
};

/**
Expand Down
Loading