Files
upstream-plane/apps/web/core/components/project/member-select.tsx
upstream-mirror 23059a1de3
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
2026-09-15 15:14:58 +05:00

114 lines
3.3 KiB
TypeScript

/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import React from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Ban } from "lucide-react";
import { Avatar } from "@makeplane/propel/components/avatar";
import { EUserProjectRoles } from "@plane/types";
// plane ui
import { CustomSearchSelect } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
// hooks
import { useMember } from "@/hooks/store/use-member";
type Props = {
value: any;
onChange: (val: string) => void;
isDisabled?: boolean;
};
export const MemberSelect = observer(function MemberSelect(props: Props) {
const { value, onChange, isDisabled = false } = props;
// router
const { projectId } = useParams();
// store hooks
const {
project: { projectMemberIds, getProjectMemberDetails },
} = useMember();
const options = projectMemberIds
?.map((userId) => {
const memberDetails = projectId ? getProjectMemberDetails(userId, projectId.toString()) : null;
if (!memberDetails?.member) return;
const isGuest = memberDetails.role === EUserProjectRoles.GUEST;
if (isGuest) return;
return {
value: `${memberDetails?.member.id}`,
query: `${memberDetails?.member.display_name}`,
content: (
<div className="flex items-center gap-2">
<Avatar
alt={memberDetails?.member.display_name}
fallback={memberDetails?.member.display_name?.[0]?.toUpperCase()}
src={getFileURL(memberDetails?.member.avatar_url)}
size="xs"
/>
{memberDetails?.member.display_name}
</div>
),
};
})
.filter((option) => !!option) as
| {
value: string;
query: string;
content: React.ReactNode;
}[]
| undefined;
const selectedOption = projectId ? getProjectMemberDetails(value, projectId.toString()) : null;
return (
<CustomSearchSelect
value={value}
label={
<div className="flex h-3.5 items-center gap-2">
{selectedOption && (
<Avatar
alt={selectedOption.member?.display_name}
fallback={selectedOption.member?.display_name?.[0]?.toUpperCase()}
src={getFileURL(selectedOption.member?.avatar_url)}
size="xs"
/>
)}
{selectedOption ? (
selectedOption.member?.display_name
) : (
<div className="flex items-center gap-2">
<Ban className="h-3.5 w-3.5 rotate-90 text-placeholder" />
<span className="text-13 text-placeholder">None</span>
</div>
)}
</div>
}
buttonClassName="!px-3 !py-2 bg-surface-1"
options={
options &&
options && [
...options,
{
value: "none",
query: "none",
content: (
<div className="flex items-center gap-2">
<Ban className="h-3.5 w-3.5 rotate-90 text-placeholder" />
<span className="py-0.5 text-13 text-placeholder">None</span>
</div>
),
},
]
}
maxHeight="md"
onChange={onChange}
disabled={isDisabled}
/>
);
});