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

This file was deleted.

1 change: 0 additions & 1 deletion apps/web/ce/components/issues/issue-modal/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./provider";
export * from "./issue-type-select";
export * from "./additional-properties";
export * from "./template-select";
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from "react";

export type TWorkItemModalAdditionalPropertiesProps = {
isDraft?: boolean;
projectId: string | null;
workItemId: string | undefined;
workspaceSlug: string;
};

export const WorkItemModalAdditionalProperties: React.FC<TWorkItemModalAdditionalPropertiesProps> = () => null;
1 change: 1 addition & 0 deletions apps/web/ce/components/issues/issue-modal/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const IssueModalProvider = observer((props: TIssueModalProviderProps) =>
handleProjectEntitiesFetch: () => Promise.resolve(),
handleTemplateChange: () => Promise.resolve(),
handleConvert: () => Promise.resolve(),
handleCreateSubWorkItem: () => Promise.resolve(),
}}
>
{children}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/core/components/cycles/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const CycleForm: React.FC<Props> = (props) => {
}}
multiple={false}
buttonVariant="border-with-text"
renderCondition={(project) => !!projectsWithCreatePermissions?.[project.id]}
renderCondition={(projectId) => !!projectsWithCreatePermissions?.[projectId]}
tabIndex={getIndex("cover_image")}
/>
</div>
Expand Down
8 changes: 4 additions & 4 deletions apps/web/core/components/dropdowns/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export * from "./member";
export * from "./member/dropdown";
export * from "./cycle";
export * from "./date-range";
export * from "./date";
export * from "./estimate";
export * from "./merged-date";
export * from "./module";
export * from "./module/dropdown";
export * from "./priority";
export * from "./project";
export * from "./state";
export * from "./project/dropdown";
export * from "./state/dropdown";
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
import { useRef, useState } from "react";
import { observer } from "mobx-react";
import { ChevronDown, LucideIcon } from "lucide-react";
// plane imports
import { useTranslation } from "@plane/i18n";
// ui
import { IUserLite } from "@plane/types";
import { ComboDropDown } from "@plane/ui";
// helpers
import { cn } from "@plane/utils";
// hooks
import { useMember } from "@/hooks/store";
import { useDropdown } from "@/hooks/use-dropdown";
// components
// local imports
import { DropdownButton } from "../buttons";
import { BUTTON_VARIANTS_WITH_TEXT } from "../constants";
import { ButtonAvatars } from "./avatar";
// constants
import { MemberOptions } from "./member-options";
// types
import { MemberDropdownProps } from "./types";

type Props = {
projectId?: string;
type TMemberDropdownBaseProps = {
getUserDetails: (userId: string) => IUserLite | undefined;
icon?: LucideIcon;
memberIds?: string[];
onClose?: () => void;
renderByDefault?: boolean;
onDropdownOpen?: () => void;
optionsClassName?: string;
memberIds?: string[];
renderByDefault?: boolean;
} & MemberDropdownProps;

export const MemberDropdown: React.FC<Props> = observer((props) => {
export const MemberDropdownBase: React.FC<TMemberDropdownBaseProps> = observer((props) => {
const { t } = useTranslation();
const {
button,
Expand All @@ -38,39 +37,37 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
disabled = false,
dropdownArrow = false,
dropdownArrowClassName = "",
optionsClassName = "",
getUserDetails,
hideIcon = false,
icon,
memberIds,
multiple,
onChange,
onClose,
onDropdownOpen,
optionsClassName = "",
placeholder = t("members"),
tooltipContent,
placement,
projectId,
renderByDefault = true,
showTooltip = false,
showUserDetails = false,
tabIndex,
tooltipContent,
value,
icon,
renderByDefault = true,
memberIds,
} = props;
// states
const [isOpen, setIsOpen] = useState(false);
// refs
const dropdownRef = useRef<HTMLDivElement | null>(null);
// popper-js refs
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
// states
const [isOpen, setIsOpen] = useState(false);

const { getUserDetails } = useMember();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const comboboxProps: any = {
const comboboxProps = {
value,
onChange,
disabled,
multiple,
};
if (multiple) comboboxProps.multiple = true;

const { handleClose, handleKeyDown, handleOnClick } = useDropdown({
dropdownRef,
Expand Down Expand Up @@ -163,19 +160,20 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
<ComboDropDown
as="div"
ref={dropdownRef}
{...comboboxProps}
className={cn("h-full", className)}
onChange={dropdownOnChange}
onKeyDown={handleKeyDown}
button={comboButton}
renderByDefault={renderByDefault}
{...comboboxProps}
>
{isOpen && (
<MemberOptions
getUserDetails={getUserDetails}
isOpen={isOpen}
memberIds={memberIds}
onDropdownOpen={onDropdownOpen}
optionsClassName={optionsClassName}
isOpen={isOpen}
projectId={projectId}
placement={placement}
referenceElement={referenceElement}
/>
Expand Down
48 changes: 48 additions & 0 deletions apps/web/core/components/dropdowns/member/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { LucideIcon } from "lucide-react";
// hooks
import { useMember } from "@/hooks/store";
// local imports
import { MemberDropdownBase } from "./base";
import { MemberDropdownProps } from "./types";

type TMemberDropdownProps = {
icon?: LucideIcon;
memberIds?: string[];
onClose?: () => void;
optionsClassName?: string;
projectId?: string;
renderByDefault?: boolean;
} & MemberDropdownProps;

export const MemberDropdown: React.FC<TMemberDropdownProps> = observer((props) => {
const { memberIds: propsMemberIds, projectId } = props;
// router params
const { workspaceSlug } = useParams();
// store hooks
const {
getUserDetails,
project: { getProjectMemberIds, fetchProjectMembers },
workspace: { workspaceMemberIds },
} = useMember();

const memberIds = propsMemberIds
? propsMemberIds
: projectId
? getProjectMemberIds(projectId, false)
: workspaceMemberIds;

const onDropdownOpen = () => {
if (!memberIds && projectId && workspaceSlug) fetchProjectMembers(workspaceSlug.toString(), projectId);
};

return (
<MemberDropdownBase
{...props}
getUserDetails={getUserDetails}
memberIds={memberIds ?? []}
onDropdownOpen={onDropdownOpen}
/>
);
});
57 changes: 22 additions & 35 deletions apps/web/core/components/dropdowns/member/member-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,48 @@
import { useEffect, useRef, useState } from "react";
import { Placement } from "@popperjs/core";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { createPortal } from "react-dom";
import { usePopper } from "react-popper";
import { Check, Search } from "lucide-react";
import { Combobox } from "@headlessui/react";
import { EUserPermissions } from "@plane/constants";
// plane imports
import { useTranslation } from "@plane/i18n";
// plane ui
import { Avatar } from "@plane/ui";
import { cn, getFileURL } from "@plane/utils";
// helpers
// hooks
import { useUser, useMember } from "@/hooks/store";
import { useUser } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";
import { IUserLite } from "@plane/types";

interface Props {
memberIds?: string[];
className?: string;
getUserDetails: (userId: string) => IUserLite | undefined;
isOpen: boolean;
memberIds?: string[];
onDropdownOpen?: () => void;
optionsClassName?: string;
projectId?: string;
referenceElement: HTMLButtonElement | null;
placement: Placement | undefined;
isOpen: boolean;
referenceElement: HTMLButtonElement | null;
}

export const MemberOptions: React.FC<Props> = observer((props: Props) => {
const { memberIds: propsMemberIds, projectId, referenceElement, placement, isOpen, optionsClassName = "" } = props;
const {
getUserDetails,
isOpen,
memberIds,
onDropdownOpen,
optionsClassName = "",
placement,
referenceElement,
} = props;
// refs
const inputRef = useRef<HTMLInputElement | null>(null);
// states
const [query, setQuery] = useState("");
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
// refs
const inputRef = useRef<HTMLInputElement | null>(null);
// store hooks
// plane hooks
const { t } = useTranslation();
const { workspaceSlug } = useParams();
const {
getUserDetails,
project: { getProjectMemberIds, fetchProjectMembers, getProjectMemberDetails },
workspace: { workspaceMemberIds },
} = useMember();
// store hooks
const { data: currentUser } = useUser();
const { isMobile } = usePlatformOS();
// popper-js init
Expand All @@ -60,22 +62,13 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {

useEffect(() => {
if (isOpen) {
onOpen();
onDropdownOpen?.();
if (!isMobile) {
inputRef.current && inputRef.current.focus();
}
}
}, [isOpen, isMobile]);

const memberIds = propsMemberIds
? propsMemberIds
: projectId
? getProjectMemberIds(projectId, true)
: workspaceMemberIds;
const onOpen = () => {
if (!memberIds && workspaceSlug && projectId) fetchProjectMembers(workspaceSlug.toString(), projectId);
};

const searchInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (query !== "" && e.key === "Escape") {
e.stopPropagation();
Expand All @@ -86,12 +79,6 @@ export const MemberOptions: React.FC<Props> = observer((props: Props) => {
const options = memberIds
?.map((userId) => {
const userDetails = getUserDetails(userId);
if (projectId) {
const role = getProjectMemberDetails(userId, projectId)?.role;
const isGuest = role === EUserPermissions.GUEST;
if (isGuest) return;
}

return {
value: userId,
query: `${userDetails?.display_name} ${userDetails?.first_name} ${userDetails?.last_name}`,
Expand Down
Loading