feat(ratecard): crud rename and ratecard-assignee-selector create

This commit is contained in:
shancds
2025-05-22 16:46:58 +05:30
parent a711d48c9c
commit 87bd1b8801
5 changed files with 209 additions and 42 deletions

View File

@@ -14,8 +14,13 @@ import {
} from '@/features/finance/project-finance-slice';
import { useParams } from 'react-router-dom';
import { jobTitlesApiService } from '@/api/settings/job-titles/job-titles.api.service';
import RateCardAssigneeSelector from '@/components/project-ratecard/ratecard-assignee-selector';
import { projectsApiService } from '@/api/projects/projects.api.service';
import { IProjectMemberViewModel } from '@/types/projectMember.types';
const RatecardTable: React.FC = () => {
const dispatch = useAppDispatch();
const { t } = useTranslation('project-view-finance');
const { projectId } = useParams();
@@ -30,6 +35,40 @@ const RatecardTable: React.FC = () => {
const [addingRow, setAddingRow] = useState<boolean>(false);
const [editingIndex, setEditingIndex] = useState<number | null>(null);
const [jobTitles, setJobTitles] = useState<RatecardType[]>([]);
const [members, setMembers] = useState<IProjectMemberViewModel[]>([]);
const [isLoadingMembers, setIsLoading] = useState(false);
const pagination = {
current: 1,
pageSize: 100,
field: 'name',
order: 'asc',
};
const getProjectMembers = async () => {
if (!projectId) return;
setIsLoading(true);
try {
const res = await projectsApiService.getMembers(
projectId,
pagination.current,
pagination.pageSize,
pagination.field,
pagination.order,
null
);
if (res.done) {
setMembers(res.body?.data || []);
}
} catch (error) {
console.error('Error fetching members:', error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
getProjectMembers();
// eslint-disable-next-line
}, []);
// Fetch job titles for selection
useEffect(() => {
@@ -72,7 +111,7 @@ const RatecardTable: React.FC = () => {
};
// Handle job title select for new row
const handleSelectJobTitle = async(jobTitleId: string) => {
const handleSelectJobTitle = async (jobTitleId: string) => {
const jobTitle = jobTitles.find((jt) => jt.id === jobTitleId);
if (!jobTitle || !projectId) return;
// Prevent duplicates
@@ -180,30 +219,24 @@ const RatecardTable: React.FC = () => {
{
title: t('membersColumn'),
dataIndex: 'members',
render: (members: string[] | null | undefined) =>
members && members.length > 0 ? (
render: (memberscol: string[] | null | undefined, record: JobRoleType, index: number) => (
<div style={{ display: 'flex', alignItems: 'center', gap: 4, position: 'relative' }}>
<Avatar.Group>
{members.map((member, i) => (
<CustomAvatar key={i} avatarName={member} size={26} />
))}
{memberscol && memberscol.length > 0 &&
memberscol.map((member, i) => (
<CustomAvatar key={i} avatarName={member} size={26} />
))}
</Avatar.Group>
) : (
<Button
shape="circle"
icon={
<PlusOutlined
style={{
fontSize: 12,
width: 22,
height: 22,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
/>
}
/>
),
<div>
<RateCardAssigneeSelector
projectId={projectId as string}
selectedMemberIds={memberscol || []}
onChange={memberId => handleMemberChange(memberId, index)}
memberlist={members}
/>
</div>
</div>
),
},
{
title: t('actions'),
@@ -225,6 +258,22 @@ const RatecardTable: React.FC = () => {
},
];
const handleMemberChange = (memberId: string, rowIndex: number) => {
setRoles(prev =>
prev.map((role, idx) => {
if (idx !== rowIndex) return role;
const members = Array.isArray(role.members) ? [...role.members] : [];
const memberIdx = members.indexOf(memberId);
if (memberIdx > -1) {
members.splice(memberIdx, 1); // remove if exists
} else {
members.push(memberId); // add if not exists
}
return { ...role, members };
})
);
};
return (
<Table
dataSource={