Skip to content

Commit 122d16b

Browse files
JXP25SoniHarsh1
andauthored
implements cascaded saperate dropdowns for programs in JAF (#262) (#264)
* implements cascaded saperate dropdowns for programs in JAF * Update JobDetails.tsx --------- Co-authored-by: Harsh Soni <98403303+SoniHarsh1@users.noreply.github.com>
1 parent 72d842e commit 122d16b

1 file changed

Lines changed: 263 additions & 50 deletions

File tree

src/components/JAF/JobDetails.tsx

Lines changed: 263 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
UploadProps,
2020
SelectProps,
2121
List,
22+
Tag,
23+
Cascader,
2224
} from "antd";
2325
import { useEffect, useState } from "react";
2426
import axios from "axios";
@@ -67,7 +69,10 @@ const JobDetails = ({
6769
const [testType, setTestType] = useState([]);
6870
const [seasonType, setSeasonType] = useState("");
6971
const [interviewType, setInterviewType] = useState([]);
70-
const [programs, setPrograms] = useState<SelectProps["options"]>([]);
72+
const [programsData, setProgramsData] = useState<any>({
73+
programs: [],
74+
coursesMap: new Map(),
75+
});
7176
let testTypeOptions: any = [];
7277
let interviewTypeOptions: any = [];
7378
const programsOptions: SelectProps["options"] = [];
@@ -120,16 +125,170 @@ const JobDetails = ({
120125
if (matchingSeason) {
121126
setSeasonType(matchingSeason.type);
122127
}
123-
res.data.programs.map((it: any) => {
124-
programsOptions.push({
125-
value: it.id,
126-
label: `${it.branch} - ${it.course} - ${it.year}`,
127-
});
128+
// Process programs data
129+
const uniqueYears = new Set<string>();
130+
const programsMap = new Map<string, Set<string>>();
131+
const branchesMap = new Map<string, Set<string>>();
132+
133+
res.data.programs.forEach((program: any) => {
134+
uniqueYears.add(program.year);
135+
136+
const yearCourseKey = program.year;
137+
if (!programsMap.has(yearCourseKey)) {
138+
programsMap.set(yearCourseKey, new Set());
139+
}
140+
programsMap.get(yearCourseKey)?.add(program.course);
141+
142+
const courseBranchKey = `${program.year}-${program.course}`;
143+
if (!branchesMap.has(courseBranchKey)) {
144+
branchesMap.set(courseBranchKey, new Set());
145+
}
146+
branchesMap.get(courseBranchKey)?.add(program.branch);
147+
});
148+
149+
setYears(Array.from(uniqueYears));
150+
setProgramsData({
151+
programs: res.data.programs,
152+
coursesMap: programsMap,
153+
branchesMap: branchesMap,
128154
});
129-
setPrograms(programsOptions);
130155
});
131156
}, []);
132157

158+
const [years, setYears] = useState<string[]>([]);
159+
const [courses, setCourses] = useState<string[]>([]);
160+
const [branches, setBranches] = useState<string[]>([]);
161+
162+
const [selectedYear, setSelectedYear] = useState<string>("");
163+
const [selectedCourse, setSelectedCourse] = useState<string>("");
164+
const [selectedBranch, setSelectedBranch] = useState<string>("");
165+
const [dropdownVisible, setDropdownVisible] = useState(false);
166+
167+
const handleYearChange = (year: string) => {
168+
setSelectedYear(year);
169+
setSelectedCourse("");
170+
setSelectedBranch("");
171+
172+
const availableCourses = Array.from(
173+
programsData.coursesMap.get(year) || [],
174+
) as string[];
175+
setCourses(availableCourses);
176+
};
177+
178+
const handleCourseChange = (course: string) => {
179+
setSelectedCourse(course);
180+
setSelectedBranch("");
181+
182+
const key = `${selectedYear}-${course}`;
183+
const availableBranches = Array.from(
184+
programsData.branchesMap.get(key) || [],
185+
) as string[];
186+
setBranches(availableBranches);
187+
};
188+
189+
const handleBranchChange = (branch: string, fieldIndex: number) => {
190+
if (branch === "ALL") {
191+
const allBranchesSelected = branches.every((branch) =>
192+
selectedPrograms.some(
193+
(p) =>
194+
p.year === selectedYear &&
195+
p.course === selectedCourse &&
196+
p.branch === branch,
197+
),
198+
);
199+
200+
if (allBranchesSelected) {
201+
const updatedPrograms = selectedPrograms.filter(
202+
(p) => !(p.year === selectedYear && p.course === selectedCourse),
203+
);
204+
setSelectedPrograms(updatedPrograms);
205+
form.setFieldValue(
206+
["salaries", fieldIndex, "programs"],
207+
updatedPrograms.map((p) => p.id),
208+
);
209+
} else {
210+
const allPrograms = programsData.programs
211+
.filter((p) => p.year === selectedYear && p.course === selectedCourse)
212+
.map((p) => ({
213+
year: p.year,
214+
course: p.course,
215+
branch: p.branch,
216+
id: p.id,
217+
}));
218+
219+
const newPrograms = allPrograms.filter(
220+
(newProg) =>
221+
!selectedPrograms.some(
222+
(existingProg) => existingProg.id === newProg.id,
223+
),
224+
);
225+
226+
const updatedPrograms = [...selectedPrograms, ...newPrograms];
227+
setSelectedPrograms(updatedPrograms);
228+
form.setFieldValue(
229+
["salaries", fieldIndex, "programs"],
230+
updatedPrograms.map((p) => p.id),
231+
);
232+
}
233+
} else {
234+
const program = programsData.programs.find(
235+
(p) =>
236+
p.year === selectedYear &&
237+
p.course === selectedCourse &&
238+
p.branch === branch,
239+
);
240+
241+
if (program) {
242+
const isSelected = selectedPrograms.some((p) => p.id === program.id);
243+
244+
if (isSelected) {
245+
const updatedPrograms = selectedPrograms.filter(
246+
(p) => p.id !== program.id,
247+
);
248+
setSelectedPrograms(updatedPrograms);
249+
form.setFieldValue(
250+
["salaries", fieldIndex, "programs"],
251+
updatedPrograms.map((p) => p.id),
252+
);
253+
} else {
254+
const newProgram = {
255+
year: program.year,
256+
course: program.course,
257+
branch: program.branch,
258+
id: program.id,
259+
};
260+
261+
const updatedPrograms = [...selectedPrograms, newProgram];
262+
setSelectedPrograms(updatedPrograms);
263+
form.setFieldValue(
264+
["salaries", fieldIndex, "programs"],
265+
updatedPrograms.map((p) => p.id),
266+
);
267+
}
268+
}
269+
}
270+
271+
setSelectedBranch("");
272+
};
273+
274+
const handleRemoveProgram = (programId: string, fieldIndex: number) => {
275+
const updatedPrograms = selectedPrograms.filter((p) => p.id !== programId);
276+
setSelectedPrograms(updatedPrograms);
277+
form.setFieldValue(
278+
["salaries", fieldIndex, "programs"],
279+
updatedPrograms.map((p) => p.id),
280+
);
281+
};
282+
283+
const [selectedPrograms, setSelectedPrograms] = useState<
284+
Array<{
285+
year: string;
286+
course: string;
287+
branch: string;
288+
id: string;
289+
}>
290+
>([]);
291+
133292
return (
134293
<Form
135294
layout="vertical"
@@ -585,15 +744,99 @@ const JobDetails = ({
585744
>
586745
<h2 className="text-sm ">Criteria</h2>
587746
<Row gutter={24}>
588-
<Col span={12}>
747+
<Col span={24}>
589748
<Form.Item label="Programs" name={[field.name, "programs"]}>
590-
<Select
591-
mode="multiple"
592-
placeholder="Please Select"
593-
options={programs}
594-
></Select>
749+
<div>
750+
<div style={{ marginBottom: "10px" }}>
751+
<Select
752+
style={{ width: "24%", marginRight: "1%" }}
753+
placeholder="Select Year"
754+
value={selectedYear || undefined}
755+
onChange={handleYearChange}
756+
options={years.map((year) => ({
757+
value: year,
758+
label: year,
759+
}))}
760+
/>
761+
<Select
762+
style={{ width: "24%", marginRight: "1%" }}
763+
placeholder="Select Course"
764+
value={selectedCourse || undefined}
765+
onChange={handleCourseChange}
766+
disabled={!selectedYear}
767+
options={courses.map((course) => ({
768+
value: course,
769+
label: course,
770+
}))}
771+
/>
772+
<Select
773+
style={{ width: "50%" }}
774+
placeholder="Select Branch"
775+
value={selectedBranch}
776+
onChange={(value) =>
777+
handleBranchChange(value, field.name)
778+
}
779+
disabled={!selectedCourse}
780+
options={[
781+
{ value: "ALL", label: "Open For All" },
782+
...branches.map((branch) => {
783+
const isSelected = selectedPrograms.some(
784+
(p) =>
785+
p.year === selectedYear &&
786+
p.course === selectedCourse &&
787+
p.branch === branch,
788+
);
789+
return {
790+
value: branch,
791+
label: branch,
792+
className: isSelected
793+
? "ant-select-item-option-selected"
794+
: "",
795+
};
796+
}),
797+
]}
798+
/>
799+
</div>
800+
801+
{selectedPrograms.length > 0 && (
802+
<div
803+
style={{
804+
marginTop: "10px",
805+
border: "1px solid #d9d9d9",
806+
borderRadius: "4px",
807+
padding: "8px",
808+
minHeight: "50px",
809+
maxHeight: "150px",
810+
overflowY: "auto",
811+
}}
812+
>
813+
<h3 className="ml-2">Selected Programs :</h3>
814+
{selectedPrograms.map((program) => (
815+
<Tag
816+
key={program.id}
817+
closable
818+
onClose={() =>
819+
handleRemoveProgram(program.id, field.name)
820+
}
821+
style={{
822+
fontSize: "14px",
823+
margin: "4px",
824+
maxWidth: "100%",
825+
overflow: "hidden",
826+
textOverflow: "ellipsis",
827+
whiteSpace: "nowrap",
828+
}}
829+
>
830+
{`${program.branch} - ${program.course} - ${program.year}`}
831+
</Tag>
832+
))}
833+
</div>
834+
)}
835+
</div>
595836
</Form.Item>
596837
</Col>
838+
</Row>
839+
<Row gutter={24}>
597840
<Col span={12}>
598841
<Form.Item label="Genders" name={[field.name, "genders"]}>
599842
<Select
@@ -607,8 +850,6 @@ const JobDetails = ({
607850
></Select>
608851
</Form.Item>
609852
</Col>
610-
</Row>
611-
<Row gutter={24}>
612853
<Col span={12}>
613854
<Form.Item
614855
label="Categories"
@@ -627,6 +868,8 @@ const JobDetails = ({
627868
></Select>
628869
</Form.Item>
629870
</Col>
871+
</Row>
872+
<Row gutter={24}>
630873
<Col span={12}>
631874
<Form.Item
632875
label="Backlogs"
@@ -644,6 +887,11 @@ const JobDetails = ({
644887
/>
645888
</Form.Item>
646889
</Col>
890+
<Col span={12}>
891+
<Form.Item label="Min CPI" name={[field.name, "minCPI"]}>
892+
<Input placeholder="Min CPI" />
893+
</Form.Item>
894+
</Col>
647895
</Row>
648896
<Row gutter={24}>
649897
<Col span={12}>
@@ -713,41 +961,6 @@ const JobDetails = ({
713961
</Form.Item>
714962
</Col>
715963
</Row>
716-
<Row gutter={24}>
717-
<Col span={12}>
718-
<Form.Item
719-
label="Min CPI"
720-
name={[field.name, "minCPI"]}
721-
rules={[
722-
{
723-
pattern: /^\d*\.?\d*$/,
724-
message: "Please enter a positive decimal value",
725-
},
726-
{
727-
validator: (_, value) => {
728-
if (value === undefined || value === "")
729-
return Promise.resolve();
730-
if (!/^\d*\.?\d*$/.test(value))
731-
return Promise.resolve();
732-
const num = parseFloat(value);
733-
if (isNaN(num) || num > 10) {
734-
return Promise.reject(
735-
"Value must be less than or equal to 10",
736-
);
737-
}
738-
return Promise.resolve();
739-
},
740-
},
741-
]}
742-
getValueFromEvent={(e) => {
743-
const value = e.target.value.replace(/\s+/g, "");
744-
return value;
745-
}}
746-
>
747-
<Input placeholder="Min CPI" />
748-
</Form.Item>
749-
</Col>
750-
</Row>
751964
{seasonType === "PLACEMENT" ? (
752965
<>
753966
<h2 className="text-sm">Placement Details</h2>

0 commit comments

Comments
 (0)