Enhance project member invitation feature with new localization and UI updates

- Added new localization strings for "invite member" and "also invite to project" across multiple languages (Albanian, German, English, Spanish, Portuguese, Chinese).
- Updated the project member invite drawer to conditionally display UI elements based on the context of the invitation (from assigner or not).
- Introduced a new state management feature to track if the invitation is initiated from the assignee selector, improving user experience.
This commit is contained in:
shancds
2025-07-22 16:21:18 +05:30
parent 3373dccc58
commit da791e2cb7
9 changed files with 41 additions and 14 deletions

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "Fto si anëtar",
"inviteNewMemberByEmail": "Fto anëtar të ri me email",
"members": "Anëtarë",
"copyProjectLink": "Kopjo lidhjen e projektit"
"copyProjectLink": "Kopjo lidhjen e projektit",
"inviteMember": "Fto anëtar",
"alsoInviteToProject": "Fto edhe në projekt"
}

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "Als Mitglied einladen",
"inviteNewMemberByEmail": "Neues Mitglied per E-Mail einladen",
"members": "Mitglieder",
"copyProjectLink": "Projektlink kopieren"
"copyProjectLink": "Projektlink kopieren",
"inviteMember": "Mitglied einladen",
"alsoInviteToProject": "Auch zum Projekt einladen"
}

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "Invite as a member",
"inviteNewMemberByEmail": "Invite new member by email",
"members": "Members",
"copyProjectLink": "Copy project link"
"copyProjectLink": "Copy project link",
"inviteMember": "Invite Member",
"alsoInviteToProject": "Also invite to project"
}

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "Invitar como miembro",
"inviteNewMemberByEmail": "Invitar nuevo miembro por correo electrónico",
"members": "Miembros",
"copyProjectLink": "Copiar enlace del proyecto"
"copyProjectLink": "Copiar enlace del proyecto",
"inviteMember": "Invitar miembro",
"alsoInviteToProject": "También invitar al proyecto"
}

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "Convidar como membro",
"inviteNewMemberByEmail": "Convidar novo membro por e-mail",
"members": "Membros",
"copyProjectLink": "Copiar link do projeto"
"copyProjectLink": "Copiar link do projeto",
"inviteMember": "Convidar membro",
"alsoInviteToProject": "Convidar também para o projeto"
}

View File

@@ -5,5 +5,7 @@
"inviteAsAMember": "邀请为成员",
"inviteNewMemberByEmail": "通过电子邮件邀请新成员",
"members": "成员",
"copyProjectLink": "复制项目链接"
"copyProjectLink": "复制项目链接",
"inviteMember": "邀请成员",
"alsoInviteToProject": "也邀请到项目"
}

View File

@@ -11,7 +11,7 @@ import { useAuthService } from '@/hooks/useAuth';
import { Avatar, Button, Checkbox } from '@/components';
import { sortTeamMembers } from '@/utils/sort-team-members';
import { useAppDispatch } from '@/hooks/useAppDispatch';
import { 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';
interface AssigneeSelectorProps {
@@ -206,6 +206,7 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
const handleInviteProjectMemberDrawer = () => {
setIsOpen(false); // Close the assignee dropdown first
dispatch(setIsFromAssigner(true));
dispatch(toggleProjectMemberDrawer()); // Then open the invite drawer
};

View File

@@ -22,7 +22,7 @@ import { teamMembersApiService } from '@/api/team-members/teamMembers.api.servic
const ProjectMemberDrawer = () => {
const { t } = useTranslation('project-view/project-member-drawer');
const { isDrawerOpen, currentMembersList, isLoading } = useAppSelector(
const { isDrawerOpen, currentMembersList, isLoading, isFromAssigner } = useAppSelector(
state => state.projectMemberReducer
);
const { projectId } = useAppSelector(state => state.projectReducer);
@@ -176,8 +176,9 @@ const ProjectMemberDrawer = () => {
);
const renderNotFoundContent = () => (
<Flex>
<Flex style={{ display: 'block'}}>
<Button
className='mb-2'
block
type="primary"
onClick={sendInviteToProject}
@@ -189,19 +190,23 @@ const ProjectMemberDrawer = () => {
{validateEmail(searchTerm) ? t('inviteAsAMember') : t('inviteNewMemberByEmail')}
</span>
</Button>
{isFromAssigner && <Flex>
<input className='mr-2' type="checkbox" checked={true} name={t('alsoInviteToProject')} id="AlsoInviteToProject" />
<label htmlFor={t('alsoInviteToProject')}>{t('alsoInviteToProject')}</label>
</Flex>}
</Flex>
);
return (
<Modal
title={
<Typography.Text style={{ fontWeight: 500, fontSize: 16 }}>{t('title')}</Typography.Text>
<Typography.Text style={{ fontWeight: 500, fontSize: 16 }}>{isFromAssigner ? t('inviteMember') : t('title')}</Typography.Text>
}
open={isDrawerOpen}
onCancel={() => dispatch(toggleProjectMemberDrawer())}
afterOpenChange={handleOpenChange}
footer={
<Button
!isFromAssigner && <Button
style={{ width: 140, fontSize: 12 }}
block
icon={<LinkOutlined />}
@@ -232,7 +237,7 @@ const ProjectMemberDrawer = () => {
/>
</Form.Item>
</Form>
<div style={{ fontSize: 14, fontWeight: 500, marginBottom: 8 }}>{t('members')}</div>
{!isFromAssigner && <><div style={{ fontSize: 14, fontWeight: 500, marginBottom: 8 }}>{t('members')}</div>
<div style={{ maxHeight: 360, minHeight: 120, overflowY: 'auto', marginBottom: 16 }}>
<List
loading={isLoading}
@@ -248,7 +253,8 @@ const ProjectMemberDrawer = () => {
</List.Item>
)}
/>
</div>
</div></>
}
</Modal>
);
};

View File

@@ -8,6 +8,7 @@ interface ProjectMembersState {
currentMembersList: IMentionMemberViewModel[];
isDrawerOpen: boolean;
isLoading: boolean;
isFromAssigner: boolean;
error: string | null;
}
@@ -16,6 +17,7 @@ const initialState: ProjectMembersState = {
currentMembersList: [],
isDrawerOpen: false,
isLoading: false,
isFromAssigner: false,
error: null,
};
@@ -89,6 +91,12 @@ const projectMembersSlice = createSlice({
reducers: {
toggleProjectMemberDrawer: state => {
state.isDrawerOpen = !state.isDrawerOpen;
if (state.isDrawerOpen === false) {
state.isFromAssigner = false;
}
},
setIsFromAssigner: (state, action: PayloadAction<boolean>) => {
state.isFromAssigner = action.payload;
},
},
extraReducers: builder => {
@@ -139,7 +147,7 @@ const projectMembersSlice = createSlice({
},
});
export const { toggleProjectMemberDrawer } = projectMembersSlice.actions;
export const { toggleProjectMemberDrawer, setIsFromAssigner } = projectMembersSlice.actions;
export {
getProjectMembers,
getAllProjectMembers,