feat(assignee-selector): enhance member invitation functionality and integrate project manager checks

- Added hooks for project manager status and authentication to manage member invitation visibility.
- Refactored dropdown toggle logic for improved readability and performance.
- Updated UI to conditionally render the invite member button based on user roles (admin or project manager).
- Cleaned up code formatting for better consistency and maintainability.
This commit is contained in:
shancds
2025-07-25 09:47:09 +05:30
parent 980af8bd4f
commit 27605b4d68

View File

@@ -13,6 +13,8 @@ import { sortTeamMembers } from '@/utils/sort-team-members';
import { useAppDispatch } from '@/hooks/useAppDispatch'; import { useAppDispatch } from '@/hooks/useAppDispatch';
import { setIsFromAssigner, toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice'; import { setIsFromAssigner, toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice';
import { updateEnhancedKanbanTaskAssignees } from '@/features/enhanced-kanban/enhanced-kanban.slice'; import { updateEnhancedKanbanTaskAssignees } from '@/features/enhanced-kanban/enhanced-kanban.slice';
import useIsProjectManager from '@/hooks/useIsProjectManager';
import { useAuthStatus } from '@/hooks/useAuthStatus';
interface AssigneeSelectorProps { interface AssigneeSelectorProps {
task: IProjectTask; task: IProjectTask;
@@ -42,6 +44,8 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
const currentSession = useAuthService().getCurrentSession(); const currentSession = useAuthService().getCurrentSession();
const { socket } = useSocket(); const { socket } = useSocket();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { isAdmin } = useAuthStatus();
const isProjectManager = useIsProjectManager();
const filteredMembers = useMemo(() => { const filteredMembers = useMemo(() => {
return teamMembers?.data?.filter(member => return teamMembers?.data?.filter(member =>
@@ -64,7 +68,7 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node) && if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node) &&
buttonRef.current && !buttonRef.current.contains(event.target as Node)) { buttonRef.current && !buttonRef.current.contains(event.target as Node)) {
setIsOpen(false); setIsOpen(false);
} }
}; };
@@ -75,8 +79,8 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
if (buttonRef.current) { if (buttonRef.current) {
const rect = buttonRef.current.getBoundingClientRect(); const rect = buttonRef.current.getBoundingClientRect();
const isVisible = rect.top >= 0 && rect.left >= 0 && const isVisible = rect.top >= 0 && rect.left >= 0 &&
rect.bottom <= window.innerHeight && rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth; rect.right <= window.innerWidth;
if (isVisible) { if (isVisible) {
updateDropdownPosition(); updateDropdownPosition();
@@ -302,12 +306,10 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
/> />
</span> </span>
{pendingChanges.has(member.id || '') && ( {pendingChanges.has(member.id || '') && (
<div className={`absolute inset-0 flex items-center justify-center ${ <div className={`absolute inset-0 flex items-center justify-center ${isDarkMode ? 'bg-gray-800/50' : 'bg-white/50'
isDarkMode ? 'bg-gray-800/50' : 'bg-white/50' }`}>
}`}> <div className={`w-3 h-3 border border-t-transparent rounded-full animate-spin ${isDarkMode ? 'border-blue-400' : 'border-blue-600'
<div className={`w-3 h-3 border border-t-transparent rounded-full animate-spin ${ }`} />
isDarkMode ? 'border-blue-400' : 'border-blue-600'
}`} />
</div> </div>
)} )}
</div> </div>
@@ -340,22 +342,26 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
</div> </div>
{/* Footer */} {/* Footer */}
<div className={`p-2 border-t ${isDarkMode ? 'border-gray-600' : 'border-gray-200'}`}>
<button {(isAdmin || isProjectManager) && (
className={` <div className={`p-2 border-t ${isDarkMode ? 'border-gray-600' : 'border-gray-200'}`}>
w-full flex items-center justify-center gap-1 px-2 py-1 text-xs rounded <button
transition-colors className={`
${isDarkMode w-full flex items-center justify-center gap-1 px-2 py-1 text-xs rounded
? 'text-blue-400 hover:bg-gray-700' transition-colors
: 'text-blue-600 hover:bg-blue-50' ${isDarkMode
} ? 'text-blue-400 hover:bg-gray-700'
`} : 'text-blue-600 hover:bg-blue-50'
onClick={handleInviteProjectMemberDrawer} }
> `}
<UserAddOutlined /> onClick={handleInviteProjectMemberDrawer}
Invite member >
</button> <UserAddOutlined />
</div> Invite member
</button>
</div>
)}
</div>, </div>,
document.body document.body
)} )}