fix: migrate ImagePickerPopover to Propel Tabs component and render only enabled tabs

- Replace custom tab implementation with Propel Tabs
- Dynamically render only enabled tabs based on configuration
- Filter tabs by isEnabled property for cleaner conditional rendering
- Improve tab navigation and accessibility with Propel components
This commit is contained in:
Prateek Shourya
2025-12-10 15:26:09 +05:30
parent 639a2aab41
commit e4ccda309f

View File

@@ -5,11 +5,12 @@ import { useDropzone } from "react-dropzone";
import type { Control } from "react-hook-form"; import type { Control } from "react-hook-form";
import { Controller } from "react-hook-form"; import { Controller } from "react-hook-form";
import useSWR from "swr"; import useSWR from "swr";
import { Tab, Popover } from "@headlessui/react"; import { Popover } from "@headlessui/react";
// plane imports // plane imports
import { ACCEPTED_COVER_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE, MAX_FILE_SIZE } from "@plane/constants"; import { ACCEPTED_COVER_IMAGE_MIME_TYPES_FOR_REACT_DROPZONE, MAX_FILE_SIZE } from "@plane/constants";
import { useOutsideClickDetector } from "@plane/hooks"; import { useOutsideClickDetector } from "@plane/hooks";
import { Button } from "@plane/propel/button"; import { Button } from "@plane/propel/button";
import { Tabs } from "@plane/propel/tabs";
import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { EFileAssetType } from "@plane/types"; import { EFileAssetType } from "@plane/types";
import { Input, Loader } from "@plane/ui"; import { Input, Loader } from "@plane/ui";
@@ -80,6 +81,8 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
[hasUnsplashConfigured] [hasUnsplashConfigured]
); );
const enabledTabs = useMemo(() => tabOptions.filter((tab) => tab.isEnabled), [tabOptions]);
const { data: unsplashImages, error: unsplashError } = useSWR( const { data: unsplashImages, error: unsplashError } = useSWR(
`UNSPLASH_IMAGES_${searchParams}`, `UNSPLASH_IMAGES_${searchParams}`,
() => fileService.getUnsplashImages(searchParams), () => fileService.getUnsplashImages(searchParams),
@@ -195,25 +198,19 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
> >
<div <div
ref={imagePickerRef} ref={imagePickerRef}
className="flex h-96 w-80 flex-col overflow-auto rounded border border-custom-border-300 bg-custom-background-100 p-3 shadow-2xl md:h-[28rem] md:w-[36rem]" className="flex h-96 w-80 flex-col overflow-auto rounded border border-custom-border-300 bg-custom-background-100 shadow-2xl md:h-[36rem] md:w-[36rem]"
> >
<Tab.Group> <Tabs defaultValue={enabledTabs[0]?.key || "images"} className="flex h-full flex-col p-3">
<Tab.List as="span" className="inline-block rounded bg-custom-background-80 p-1"> <Tabs.List className="flex rounded bg-custom-background-80 p-1">
{tabOptions.map((tab) => ( {enabledTabs.map((tab) => (
<Tab <Tabs.Trigger key={tab.key} value={tab.key} size="md">
key={tab.key}
className={({ selected }) =>
`rounded px-4 py-1 text-center text-sm outline-none transition-colors ${
selected ? "bg-custom-primary text-white" : "text-custom-text-100"
}`
}
>
{tab.title} {tab.title}
</Tab> </Tabs.Trigger>
))} ))}
</Tab.List> <Tabs.Indicator />
<Tab.Panels className="vertical-scrollbar scrollbar-md h-full w-full flex-1 overflow-y-auto overflow-x-hidden"> </Tabs.List>
<Tab.Panel className="mt-4 h-full w-full space-y-4"> <div className="vertical-scrollbar scrollbar-sm p-3 mt-3 flex-1 overflow-y-auto overflow-x-hidden">
<Tabs.Content value="unsplash" className="h-full w-full space-y-4">
{(unsplashImages || !unsplashError) && ( {(unsplashImages || !unsplashError) && (
<> <>
<div className="flex gap-x-2"> <div className="flex gap-x-2">
@@ -280,8 +277,8 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
)} )}
</> </>
)} )}
</Tab.Panel> </Tabs.Content>
<Tab.Panel className="mt-4 h-full w-full space-y-4"> <Tabs.Content value="images" className="h-full w-full space-y-4">
<div className="grid grid-cols-4 gap-4"> <div className="grid grid-cols-4 gap-4">
{Object.values(STATIC_COVER_IMAGES).map((imageUrl, index) => ( {Object.values(STATIC_COVER_IMAGES).map((imageUrl, index) => (
<div <div
@@ -297,8 +294,8 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
</div> </div>
))} ))}
</div> </div>
</Tab.Panel> </Tabs.Content>
<Tab.Panel className="mt-4 h-full w-full"> <Tabs.Content value="upload" className="h-full w-full">
<div className="flex h-full w-full flex-col gap-y-2"> <div className="flex h-full w-full flex-col gap-y-2">
<div className="flex w-full flex-1 items-center gap-3"> <div className="flex w-full flex-1 items-center gap-3">
<div <div
@@ -361,13 +358,13 @@ export const ImagePickerPopover = observer(function ImagePickerPopover(props: Pr
disabled={!image} disabled={!image}
loading={isImageUploading} loading={isImageUploading}
> >
{isImageUploading ? "Uploading..." : "Upload & Save"} {isImageUploading ? "Uploading" : "Upload & Save"}
</Button> </Button>
</div> </div>
</div> </div>
</Tab.Panel> </Tabs.Content>
</Tab.Panels> </div>
</Tab.Group> </Tabs>
</div> </div>
</Popover.Panel> </Popover.Panel>
)} )}