import Path from '@/components/common/folder/Path'; import { getTeamMembers } from '@/web/support/user/team/api'; import { getGroupList } from '@/web/support/user/team/group/api'; import useOrg from '@/web/support/user/team/org/hooks/useOrg'; import { useUserStore } from '@/web/support/user/useUserStore'; import { ChevronDownIcon } from '@chakra-ui/icons'; import { Box, Button, Flex, Grid, HStack, ModalBody, ModalFooter, Text } from '@chakra-ui/react'; import { DEFAULT_ORG_AVATAR, DEFAULT_TEAM_AVATAR, DEFAULT_USER_AVATAR } from '@fastgpt/global/common/system/constants'; import { type UpdateClbPermissionProps } from '@fastgpt/global/support/permission/collaborator'; import { type MemberGroupListItemType } from '@fastgpt/global/support/permission/memberGroup/type'; import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant'; import { type OrgListItemType } from '@fastgpt/global/support/user/team/org/type'; import { type TeamMemberItemType } from '@fastgpt/global/support/user/team/type'; import MyAvatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import SearchInput from '@fastgpt/web/components/common/Input/SearchInput'; import MyModal from '@fastgpt/web/components/common/MyModal'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination'; import { useTranslation } from 'next-i18next'; import { type ValueOf } from 'next/dist/shared/lib/constants'; import { useMemo, useRef, useState } from 'react'; import { useContextSelector } from 'use-context-selector'; import { CollaboratorContext } from './context'; import MemberItemCard from './MemberItemCard'; import PermissionSelect from './PermissionSelect'; const HoverBoxStyle = { bgColor: 'myGray.50', cursor: 'pointer' }; function MemberModal({ onClose, addPermissionOnly: addOnly = false }: { onClose: () => void; addPermissionOnly?: boolean; }) { const { t } = useTranslation(); const { userInfo } = useUserStore(); const collaboratorList = useContextSelector(CollaboratorContext, (v) => v.collaboratorList); const [filterClass, setFilterClass] = useState<'member' | 'org' | 'group'>(); const { paths, onClickOrg, members: orgMembers, MemberScrollData: OrgMemberScrollData, onPathClick, orgs, searchKey, setSearchKey } = useOrg({ withPermission: false }); const { data: members, ScrollData: TeamMemberScrollData, refreshList } = useScrollPagination(getTeamMembers, { pageSize: 15, params: { withPermission: true, withOrgs: true, status: 'active', searchKey }, throttleWait: 500, debounceWait: 200, refreshDeps: [searchKey] }); const { data: groups = [], loading: loadingGroupsAndOrgs, runAsync: refreshGroups } = useRequest2( async () => { if (!userInfo?.team?.teamId) return []; return getGroupList({ withMembers: false, searchKey }); }, { manual: false, refreshDeps: [userInfo?.team?.teamId] } ); const [selectedOrgList, setSelectedOrgIdList] = useState([]); const [selectedMemberList, setSelectedMemberList] = useState< Omit[] >([]); const [selectedGroupList, setSelectedGroupList] = useState[]>([]); const permissionList = useContextSelector(CollaboratorContext, (v) => v.permissionList); const getPerLabelList = useContextSelector(CollaboratorContext, (v) => v.getPerLabelList); const [selectedPermission, setSelectedPermission] = useState( permissionList?.read?.value ); const perLabel = useMemo(() => { if (selectedPermission === undefined) return ''; return getPerLabelList(selectedPermission!).join('、'); }, [getPerLabelList, selectedPermission]); const onUpdateCollaborators = useContextSelector( CollaboratorContext, (v) => v.onUpdateCollaborators ); const { runAsync: onConfirm, loading: isUpdating } = useRequest2( () => onUpdateCollaborators({ members: selectedMemberList.map((item) => item.tmbId), groups: selectedGroupList.map((item) => item._id), orgs: selectedOrgList.map((item) => item._id), permission: addOnly ? undefined : selectedPermission! } as UpdateClbPermissionProps>), { successToast: t('common:add_success'), onSuccess() { onClose(); } } ); const entryList = useRef([ { label: t('user:team.group.members'), icon: DEFAULT_USER_AVATAR, value: 'member' }, { label: t('user:team.org.org'), icon: DEFAULT_ORG_AVATAR, value: 'org' }, { label: t('user:team.group.group'), icon: DEFAULT_TEAM_AVATAR, value: 'group' } ]); const selectedList = useMemo(() => { return [ ...selectedOrgList.map((item) => ({ id: `org-${item._id}`, avatar: item.avatar, name: item.name, onDelete: () => setSelectedOrgIdList(selectedOrgList.filter((v) => v._id !== item._id)), orgs: undefined })), ...selectedGroupList.map((item) => ({ id: `group-${item._id}`, avatar: item.avatar, name: item.name === DefaultGroupName ? userInfo?.team.teamName : item.name, onDelete: () => setSelectedGroupList(selectedGroupList.filter((v) => v._id !== item._id)), orgs: undefined })), ...selectedMemberList.map((item) => ({ id: `member-${item.tmbId}`, avatar: item.avatar, name: item.memberName, onDelete: () => setSelectedMemberList(selectedMemberList.filter((v) => v.tmbId !== item.tmbId)), orgs: item.orgs })) ]; }, [selectedOrgList, selectedGroupList, selectedMemberList, userInfo?.team.teamName]); return ( setSearchKey(e.target.value)} /> {/* Entry */} {!searchKey && !filterClass && ( <> {entryList.current.map((item) => { return ( setFilterClass(item.value as any)} > {item.label} ); })} )} {/* Path */} {!searchKey && filterClass && ( { if (parentId === '') { setFilterClass(undefined); onPathClick(''); } else if ( parentId === 'member' || parentId === 'org' || parentId === 'group' ) { setFilterClass(parentId); onPathClick(''); } else { onPathClick(parentId); } }} rootName={t('common:Team')} /> )} {(filterClass === 'member' || searchKey) && (() => { const Members = members?.map((member) => { const onChange = () => { setSelectedMemberList((state) => { if (state.find((v) => v.tmbId === member.tmbId)) { return state.filter((v) => v.tmbId !== member.tmbId); } return [...state, member]; }); }; const collaborator = collaboratorList?.find((v) => v.tmbId === member.tmbId); return ( v.tmbId === member.tmbId)} orgs={member.orgs} /> ); }); return searchKey ? ( Members ) : ( {Members} ); })()} {(filterClass === 'org' || searchKey) && (() => { const Orgs = orgs?.map((org) => { const onChange = () => { setSelectedOrgIdList((state) => { if (state.find((v) => v._id === org._id)) { return state.filter((v) => v._id !== org._id); } return [...state, org]; }); }; const collaborator = collaboratorList?.find((v) => v.orgId === org._id); return ( String(v._id) === String(org._id))} rightSlot={ org.total && ( { onClickOrg(org); // setPath(getOrgChildrenPath(org)); e.stopPropagation(); }} /> ) } /> ); }); return searchKey ? ( Orgs ) : ( {Orgs} {orgMembers.map((member) => { const isChecked = !!selectedMemberList.find( (v) => v.tmbId === member.tmbId ); const collaborator = collaboratorList?.find( (v) => v.tmbId === member.tmbId ); return ( { setSelectedMemberList((state) => { if (state.find((v) => v.tmbId === member.tmbId)) { return state.filter((v) => v.tmbId !== member.tmbId); } return [...state, member]; }); }} isChecked={isChecked} permission={collaborator?.permission.value} addOnly={addOnly && !!member.permission.value} orgs={member.orgs} /> ); })} ); })()} {(filterClass === 'group' || searchKey) && groups?.map((group) => { const onChange = () => { setSelectedGroupList((state) => { if (state.find((v) => v._id === group._id)) { return state.filter((v) => v._id !== group._id); } return [...state, group]; }); }; const collaborator = collaboratorList?.find((v) => v.groupId === group._id); return ( v._id === group._id)} addOnly={addOnly} /> ); })} {`${t('user:has_chosen')}: `} {selectedMemberList.length + selectedGroupList.length + selectedOrgList.length} {selectedList.map((item) => { return ( ); })} {!addOnly && !!permissionList && ( {t(perLabel as any)} } onChange={(v) => setSelectedPermission(v)} /> )} {addOnly && ( {t('user:permission_add_tip')} )} ); } export default MemberModal;