From 39728d4cc4ec7cbce843bcf3ffbad82ebf0c66cd Mon Sep 17 00:00:00 2001 From: Jayash Tripathy <76092296+JayashTripathy@users.noreply.github.com> Date: Wed, 24 Dec 2025 19:30:01 +0530 Subject: [PATCH] [WEB-5779] fix: handle loading state while fetching project cover image (#8419) * refactor: replace cover image handling with CoverImage component across profile and project forms * fix: extend CoverImage component to accept additional img props * Update apps/web/core/components/common/cover-image.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: handle undefined cover image URL in ProfileSidebar component --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../core/components/common/cover-image.tsx | 44 +++++++++++++++++++ apps/web/core/components/profile/form.tsx | 9 ++-- apps/web/core/components/profile/sidebar.tsx | 14 +++--- apps/web/core/components/project/card.tsx | 8 ++-- .../core/components/project/create/header.tsx | 15 +++---- apps/web/core/components/project/form.tsx | 9 ++-- 6 files changed, 68 insertions(+), 31 deletions(-) create mode 100644 apps/web/core/components/common/cover-image.tsx diff --git a/apps/web/core/components/common/cover-image.tsx b/apps/web/core/components/common/cover-image.tsx new file mode 100644 index 0000000000..d0b410bfc3 --- /dev/null +++ b/apps/web/core/components/common/cover-image.tsx @@ -0,0 +1,44 @@ +import { cn } from "@plane/utils"; +// helpers +import { getCoverImageDisplayURL, DEFAULT_COVER_IMAGE_URL } from "@/helpers/cover-image.helper"; + +type TCoverImageProps = { + /** The cover image URL - can be static, uploaded, or external */ + src: string | null | undefined; + /** Alt text for the image */ + alt?: string; + /** Additional className for the image or skeleton */ + className?: string; + /** Whether to show default image when src is null/undefined. If false, shows loading skeleton */ + showDefaultWhenEmpty?: boolean; + /** Custom fallback URL to use instead of DEFAULT_COVER_IMAGE_URL */ + fallbackUrl?: string; +} & React.ComponentProps<"img">; + +/** + * A reusable cover image component that handles: + * - Loading states with skeleton + * - Static images (local assets) + * - Uploaded images (processed through getFileURL) + * - External URLs + * - Fallback to default cover image + */ +export function CoverImage(props: TCoverImageProps) { + const { + src, + alt = "Cover image", + className, + showDefaultWhenEmpty = false, + fallbackUrl = DEFAULT_COVER_IMAGE_URL, + ...restProps + } = props; + + // Show loading skeleton when src is undefined/null and we don't want to show default + if (!src && !showDefaultWhenEmpty) { + return
; + } + + const displayUrl = getCoverImageDisplayURL(src, fallbackUrl); + + return