Skip to content
Merged
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
94 changes: 46 additions & 48 deletions web/core/components/onboarding/invite-members.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import {
useForm,
} from "react-hook-form";
// icons
import { usePopper } from "react-popper";
import { Check, ChevronDown, Plus, XCircle } from "lucide-react";
import { Listbox, Transition } from "@headlessui/react";
import { Listbox } from "@headlessui/react";
// types
import { IUser, IWorkspace } from "@plane/types";
// ui
Expand All @@ -28,7 +29,6 @@ import { ROLE, ROLE_DETAILS } from "@/constants/workspace";
import { getUserRole } from "@/helpers/user.helper";
// hooks
import { useEventTracker } from "@/hooks/store";
import useDynamicDropdownPosition from "@/hooks/use-dynamic-dropdown";
// plane web constants
import { EUserPermissions } from "@/plane-web/constants/user-permissions";
// services
Expand Down Expand Up @@ -101,12 +101,8 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
watch,
} = props;

const buttonRef = useRef<HTMLButtonElement>(null);
const dropdownRef = useRef<HTMLDivElement>(null);

const [isDropdownOpen, setIsDropdownOpen] = useState(false);

useDynamicDropdownPosition(isDropdownOpen, () => setIsDropdownOpen(false), buttonRef, dropdownRef);
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);

const email = watch(`emails.${index}.email`);

Expand Down Expand Up @@ -134,6 +130,18 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
}
};

const { styles, attributes } = usePopper(referenceElement, popperElement, {
placement: "bottom-end",
modifiers: [
{
name: "preventOverflow",
options: {
padding: 12,
},
},
],
});

return (
<div>
<div className="group relative grid grid-cols-10 gap-4">
Expand Down Expand Up @@ -177,15 +185,13 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
value={value}
onChange={(val) => {
onChange(val);
setIsDropdownOpen(false);
setValue(`emails.${index}.role_active`, true);
}}
className="w-full flex-shrink-0 text-left"
>
<Listbox.Button
type="button"
ref={buttonRef}
onClick={() => setIsDropdownOpen((prev) => !prev)}
ref={setReferenceElement}
className="flex w-full items-center justify-between gap-1 rounded-md px-2.5 py-2 text-sm border-[0.5px] border-onboarding-border-100"
>
<span
Expand All @@ -207,45 +213,37 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
/>
</Listbox.Button>

<Transition
show={isDropdownOpen}
as={React.Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Listbox.Options
ref={dropdownRef}
className="fixed z-10 mt-1 h-fit w-48 sm:w-60 overflow-y-auto rounded-md border border-onboarding-border-100 bg-onboarding-background-200 shadow-sm focus:outline-none"
<Listbox.Options as="div">
<div
className="p-2 absolute space-y-1 z-10 mt-1 h-fit w-48 sm:w-60 rounded-md border border-onboarding-border-100 bg-onboarding-background-200 shadow-sm focus:outline-none"
ref={setPopperElement}
style={styles.popper}
{...attributes.popper}
>
<div className="space-y-1 p-2">
{Object.entries(ROLE_DETAILS).map(([key, value]) => (
<Listbox.Option
key={key}
value={parseInt(key)}
className={({ active, selected }) =>
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
active || selected ? "bg-onboarding-background-400/40" : ""
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
}
>
{({ selected }) => (
<div className="flex items-center text-wrap gap-2 p-1">
<div className="flex flex-col">
<div className="text-sm font-medium">{value.title}</div>
<div className="flex text-xs text-custom-text-300">{value.description}</div>
</div>
{selected && <Check className="h-4 w-4 shrink-0" />}
{Object.entries(ROLE_DETAILS).map(([key, value]) => (
<Listbox.Option
as="div"
key={key}
value={parseInt(key)}
className={({ active, selected }) =>
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
active || selected ? "bg-onboarding-background-400/40" : ""
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
}
>
{({ selected }) => (
<div className="flex items-center text-wrap gap-2 p-1">
<div className="flex flex-col">
<div className="text-sm font-medium">{value.title}</div>
<div className="flex text-xs text-custom-text-300">{value.description}</div>
</div>
)}
</Listbox.Option>
))}
</div>
</Listbox.Options>
</Transition>
{selected && <Check className="h-4 w-4 shrink-0" />}
</div>
)}
</Listbox.Option>
))}
</div>
</Listbox.Options>
</Listbox>
)}
/>
Expand Down
Loading