replaces course and programme api for learner #10

Merged
PriyanshuVishwakarma merged 1 commits from priyanshu-dev into main 2026-04-14 08:26:53 +00:00
2 changed files with 59 additions and 24 deletions

View File

@@ -42,7 +42,6 @@ import {
useBulkAssignProgrammeMutation,
useBulkRevokeCourseMutation,
useBulkCreateLearnersForHrMutation,
useGetCoursesForHrQuery,
useGetAssignedCoursesForOrganizationQuery,
useGetLearnerCoursesQuery,
useGetProgrammesForHrQuery,
@@ -91,6 +90,8 @@ const LearnersPage: React.FC = () => {
const [showEditDrawer, setShowEditDrawer] = useState(false);
const [selectedProgrammeId, setSelectedProgrammeId] = useState('');
const [selectedCourseId, setSelectedCourseId] = useState('');
const [courseStartDate, setCourseStartDate] = useState('');
const [courseEndDate, setCourseEndDate] = useState('');
const [assignError, setAssignError] = useState('');
const [assignCourseError, setAssignCourseError] = useState('');
const [editingEmployee, setEditingEmployee] = useState<Employee | null>(null);
@@ -169,14 +170,13 @@ const LearnersPage: React.FC = () => {
offset: 0,
});
const {
data: coursesResponse,
isLoading: coursesLoading,
refetch: refetchCourses
} = useGetCoursesForHrQuery({
limit: 100,
offset: 0,
});
data: bulkAssignCoursesResponse,
isLoading: bulkAssignCoursesLoading,
} = useGetAssignedCoursesForOrganizationQuery(
{ limit: 100, offset: 0 },
{ skip: !showAssignCourseModal }
);
const { data: learnerCoursesResponse, refetch: refetchLearnerCourses, isLoading: learnerCoursesLoading } =
useGetLearnerCoursesQuery(editingEmployee?.id ?? '', {
skip: !editingEmployee?.id,
@@ -454,6 +454,8 @@ const LearnersPage: React.FC = () => {
const response = await bulkAssignCourse({
principal_xids: [editingEmployee.id],
course_xids: [courseId],
start_date: courseStartDate,
end_date: courseEndDate,
}).unwrap();
await refetchLearnerCourses();
@@ -737,11 +739,21 @@ const LearnersPage: React.FC = () => {
setAssignCourseError('Please select a course.');
return;
}
if (!courseStartDate || !courseEndDate) {
setAssignCourseError('Please select start date and end date.');
return;
}
if (new Date(courseEndDate) < new Date(courseStartDate)) {
setAssignCourseError('End date cannot be before start date.');
return;
}
try {
const response = await bulkAssignCourse({
principal_xids: selectedEmployees,
course_xids: [selectedCourseId],
start_date: courseStartDate,
end_date: courseEndDate,
}).unwrap();
showToast(
@@ -751,6 +763,8 @@ const LearnersPage: React.FC = () => {
);
setShowAssignCourseModal(false);
setSelectedCourseId('');
setCourseStartDate('');
setCourseEndDate('');
setSelectedEmployees([]);
} catch (error: any) {
const message = error?.data?.message || 'Failed to assign course.';
@@ -1446,7 +1460,7 @@ const LearnersPage: React.FC = () => {
<SelectValue placeholder={programmesLoading ? 'Loading programmes...' : 'Choose programme'} />
</SelectTrigger>
<SelectContent>
{(programmesResponse?.data?.items ?? []).map((programme) => (
{(programmesResponse?.data ?? []).map((programme) => (
<SelectItem key={programme.id} value={programme.id}>
{programme.programme_title}
</SelectItem>
@@ -1501,10 +1515,12 @@ const LearnersPage: React.FC = () => {
</label>
<Select value={selectedCourseId} onValueChange={setSelectedCourseId}>
<SelectTrigger>
<SelectValue placeholder={coursesLoading ? 'Loading courses...' : 'Choose course'} />
<SelectValue
placeholder={bulkAssignCoursesLoading ? 'Loading courses...' : 'Choose course'}
/>
</SelectTrigger>
<SelectContent>
{(coursesResponse?.data?.items ?? []).map((course) => (
{(bulkAssignCoursesResponse?.data ?? []).map((course) => (
<SelectItem key={course.id} value={course.id}>
{course.course_name}
</SelectItem>
@@ -1512,6 +1528,24 @@ const LearnersPage: React.FC = () => {
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div>
<label className="block text-sm font-medium mb-2">Start Date</label>
<Input
type="date"
value={courseStartDate}
onChange={(e) => setCourseStartDate(e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">End Date</label>
<Input
type="date"
value={courseEndDate}
onChange={(e) => setCourseEndDate(e.target.value)}
/>
</div>
</div>
<div className="flex gap-2 pt-4">
<Button
className="flex-1"
@@ -1526,6 +1560,8 @@ const LearnersPage: React.FC = () => {
setShowAssignCourseModal(false);
setAssignCourseError('');
setSelectedCourseId('');
setCourseStartDate('');
setCourseEndDate('');
}}
className="flex-1"
disabled={isAssigningCourse}
@@ -1615,11 +1651,13 @@ const LearnersPage: React.FC = () => {
type="button"
variant="default"
onClick={() => {
if (showOrgCoursesCatalog) {
void refetchOrgCourses();
} else {
setShowOrgCoursesCatalog(true);
}
if (!editingEmployee) return;
setSelectedEmployees([editingEmployee.id]);
setAssignCourseError('');
setSelectedCourseId('');
setCourseStartDate('');
setCourseEndDate('');
setShowAssignCourseModal(true);
}}
disabled={!editingEmployee}
className="h-9 shrink-0 rounded-md"

View File

@@ -127,12 +127,7 @@ interface ProgrammeListResponse {
success: boolean;
status: number;
message: string;
data: {
total_count: number;
limit: number;
offset: number;
items: ProgrammeItem[];
};
data: ProgrammeItem[];
errors: unknown;
correlation_id: string;
}
@@ -214,6 +209,8 @@ interface CourseListResponse {
interface BulkAssignCourseRequest {
principal_xids: string[];
course_xids: string[];
start_date: string;
end_date: string;
principal_organization_course_link_xid?: string;
}
@@ -358,7 +355,7 @@ export const learnersApi = createApi({
}),
getProgrammesForHr: builder.query<ProgrammeListResponse, ProgrammeListQueryParams>({
query: (params) => ({
url: '/hr/programme-course/programme/list',
url: '/hr/organization/list/assigned-programmes',
method: 'GET',
params: {
limit: params.limit,