Skip to content

Commit c71b026

Browse files
authored
Merge pull request #238 from dump-hr/ninom5/228-fix-interns-filtering
228 fix interns filtering
2 parents 9089b4a + 8b1391c commit c71b026

File tree

5 files changed

+327
-123
lines changed

5 files changed

+327
-123
lines changed

apps/web/src/components/InternFilter/InternFilter.tsx

Lines changed: 40 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,58 @@
1-
import { InputHandler } from '@components/index';
21
import {
3-
Discipline,
4-
DisciplineStatus,
5-
InternStatus,
6-
InterviewStatus,
7-
Question,
8-
QuestionType,
9-
TestStatus,
10-
} from '@internship-app/types';
2+
getInitialCriteria,
3+
getNewCriteria,
4+
InputHandler,
5+
} from '@components/index';
6+
import { CriteriaSection, QuestionType } from '@internship-app/types';
117
import AddIcon from '@mui/icons-material/Add';
128
import CloseIcon from '@mui/icons-material/Close';
139
import { Box, Button, IconButton } from '@mui/material';
14-
import { useState } from 'react';
10+
import { useEffect, useState } from 'react';
1511
import { FieldValues, useForm } from 'react-hook-form';
1612

17-
type CriteriaSection = {
18-
id: string;
19-
questions: Question[];
20-
};
21-
22-
const initialCriteria: CriteriaSection[] = [
23-
{
24-
id: 'main',
25-
questions: [
26-
{
27-
id: 'main.name',
28-
type: QuestionType.Field,
29-
registerValue: '',
30-
question: 'Ime/mail/testid',
31-
},
32-
{
33-
id: 'main.status',
34-
type: QuestionType.Select,
35-
registerValue: '',
36-
options: ['', ...Object.keys(InternStatus)],
37-
question: 'Status',
38-
},
39-
{
40-
id: 'main.interviewStatus',
41-
type: QuestionType.Select,
42-
registerValue: '',
43-
options: ['', ...Object.keys(InterviewStatus)],
44-
question: 'Intervju',
45-
},
46-
],
47-
},
48-
];
49-
50-
const getNewCriteria = (id: string): CriteriaSection => ({
51-
id,
52-
questions: [
53-
{
54-
id: `${id}.discipline`,
55-
type: QuestionType.Select,
56-
registerValue: Discipline.Development,
57-
options: Object.keys(Discipline),
58-
question: 'Područje',
59-
},
60-
{
61-
id: `${id}.status`,
62-
type: QuestionType.Select,
63-
registerValue: '',
64-
options: ['', ...Object.keys(DisciplineStatus)],
65-
question: 'Status',
66-
},
67-
{
68-
id: `${id}.testStatus`,
69-
type: QuestionType.Select,
70-
registerValue: '',
71-
options: ['', ...Object.keys(TestStatus)],
72-
question: 'Test',
73-
},
74-
{
75-
id: `${id}.score`,
76-
type: QuestionType.Field,
77-
registerValue: '',
78-
question: 'Bodovi (eg >15)',
79-
},
80-
{
81-
id: `${id}.not`,
82-
type: QuestionType.Checkbox,
83-
registerValue: false,
84-
question: 'Not',
85-
},
86-
],
87-
});
88-
8913
type InternFilterProps = {
9014
submitHandler: (values: FieldValues) => void;
9115
disabled?: boolean;
16+
initialValues?: FieldValues;
9217
};
9318

9419
export const InternFilter = ({
9520
submitHandler,
9621
disabled,
22+
initialValues,
9723
}: InternFilterProps) => {
98-
const form = useForm();
99-
const { unregister, handleSubmit } = form;
100-
const [criteria, setCriteria] = useState(initialCriteria);
24+
const form = useForm({
25+
shouldUnregister: true,
26+
defaultValues: initialValues,
27+
});
28+
const { handleSubmit, reset } = form;
29+
const [criteria, setCriteria] = useState<CriteriaSection[]>(() =>
30+
getInitialCriteria(initialValues?.main ?? null),
31+
);
32+
33+
// Load initial values and criteria from URL params
34+
useEffect(() => {
35+
if (!initialValues) return;
36+
37+
reset(initialValues);
38+
const disciplines = initialValues.disciplines ?? {};
39+
const main = initialValues.main ?? null;
40+
const disciplineSections = [];
41+
42+
if (Object.keys(disciplines).length > 0) {
43+
for (const key in disciplines) {
44+
const discipline = disciplines[key];
45+
const sectionId = key.startsWith('disciplines.')
46+
? key
47+
: `disciplines.${key}`;
48+
49+
const disciplineSection = getNewCriteria(sectionId, discipline);
50+
disciplineSections.push(disciplineSection);
51+
}
52+
}
53+
54+
setCriteria([...getInitialCriteria(main), ...disciplineSections]);
55+
}, [initialValues, reset]);
10156

10257
const addDisciplineSection = () => {
10358
const id = `disciplines.${crypto.randomUUID()}`;
@@ -106,7 +61,6 @@ export const InternFilter = ({
10661

10762
const removeDisciplineSection = (id: string) => {
10863
setCriteria((prev) => prev.filter((c) => c.id !== id));
109-
unregister(id);
11064
};
11165

11266
return (

apps/web/src/components/InternFilter/filter.ts

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import {
2+
CriteriaSection,
23
Discipline,
34
DisciplineStatus,
45
InternForDashboard,
56
InternStatus,
67
InterviewStatus,
8+
MainCriteria,
9+
QuestionType,
710
TestStatus,
811
} from '@internship-app/types';
912
import toast from 'react-hot-toast';
1013

1114
type DisciplineCriteria = {
12-
discipline: Discipline;
15+
discipline: Discipline | '';
1316
status: DisciplineStatus | '';
1417
testStatus: TestStatus | '';
1518
score: string | '';
@@ -79,3 +82,78 @@ export const getInternFilter =
7982

8083
return true;
8184
};
85+
86+
export const getInitialCriteria = (
87+
main: MainCriteria | null = null,
88+
): CriteriaSection[] => [
89+
{
90+
id: 'main',
91+
questions: [
92+
{
93+
id: 'main.name',
94+
type: QuestionType.Field,
95+
registerValue: main?.name || '',
96+
question: 'Ime/mail/testid',
97+
},
98+
{
99+
id: 'main.status',
100+
type: QuestionType.Select,
101+
registerValue: main?.status || '',
102+
options: ['', ...Object.keys(InternStatus)],
103+
question: 'Status',
104+
},
105+
{
106+
id: 'main.interviewStatus',
107+
type: QuestionType.Select,
108+
registerValue: main?.interviewStatus || '',
109+
options: ['', ...Object.keys(InterviewStatus)],
110+
question: 'Intervju',
111+
},
112+
],
113+
},
114+
];
115+
116+
export const getNewCriteria = (
117+
id: string,
118+
criteria: DisciplineCriteria | null = null,
119+
): CriteriaSection => ({
120+
id,
121+
questions: [
122+
{
123+
id: `${id}.discipline`,
124+
type: QuestionType.Select,
125+
registerValue:
126+
criteria && Object.prototype.hasOwnProperty.call(criteria, 'discipline')
127+
? criteria.discipline
128+
: Discipline.Development,
129+
options: Object.keys(Discipline),
130+
question: 'Područje',
131+
},
132+
{
133+
id: `${id}.status`,
134+
type: QuestionType.Select,
135+
registerValue: criteria?.status || '',
136+
options: ['', ...Object.keys(DisciplineStatus)],
137+
question: 'Status',
138+
},
139+
{
140+
id: `${id}.testStatus`,
141+
type: QuestionType.Select,
142+
registerValue: criteria?.testStatus || '',
143+
options: ['', ...Object.keys(TestStatus)],
144+
question: 'Test',
145+
},
146+
{
147+
id: `${id}.score`,
148+
type: QuestionType.Field,
149+
registerValue: criteria?.score || '',
150+
question: 'Bodovi (eg >15)',
151+
},
152+
{
153+
id: `${id}.not`,
154+
type: QuestionType.Checkbox,
155+
registerValue: criteria?.not || false,
156+
question: 'Not',
157+
},
158+
],
159+
});

apps/web/src/pages/DashboardPage/DashboardPage.tsx

Lines changed: 24 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import {
1313
Discipline,
1414
DisciplineStatus,
15-
Intern,
1615
InternStatus,
1716
InterviewStatus,
1817
} from '@internship-app/types';
@@ -22,41 +21,20 @@ import { useState } from 'react';
2221
import { FieldValues } from 'react-hook-form';
2322

2423
import c from './DashboardPage.module.css';
25-
26-
const getInternStatus = (intern: Intern) => {
27-
if (
28-
intern.internDisciplines.some(
29-
(ind) => ind.status === DisciplineStatus.Pending,
30-
)
31-
)
32-
return InternStatus.Pending;
33-
34-
if (
35-
intern.internDisciplines.some(
36-
(ind) => ind.status === DisciplineStatus.Approved,
37-
)
38-
)
39-
return InternStatus.Approved;
40-
41-
return InternStatus.Rejected;
42-
};
43-
44-
const initialState: { filterCriteria: FilterCriteria } = {
45-
filterCriteria: {
46-
main: { name: '', status: '', interviewStatus: '' },
47-
disciplines: {},
48-
},
49-
};
24+
import {
25+
deserializeFilters,
26+
getFullName,
27+
getInternStatus,
28+
serializeFilters,
29+
} from './helpers';
5030

5131
export const DashboardPage = () => {
5232
const [selection, setSelection] = useState<string[]>([]);
5333
const [emailDialogOpen, setEmailDialogOpen] = useState(false);
5434
const [actionsOpen, setActionsOpen] = useState(false);
55-
const toggleActions = () => setActionsOpen((prev) => !prev);
5635
const [showDuplicates, setShowDuplicates] = useState(false);
57-
58-
const [filterCriteria, setFilterCriteria] = useState<FilterCriteria>(
59-
initialState.filterCriteria,
36+
const [filterCriteria, setFilterCriteria] = useState<FilterCriteria>(() =>
37+
deserializeFilters(),
6038
);
6139

6240
const { data: interns } = useFetchAllInterns();
@@ -66,8 +44,18 @@ export const DashboardPage = () => {
6644
status: getInternStatus(intern),
6745
}));
6846

47+
const toggleActions = () => setActionsOpen((prev) => !prev);
48+
6949
const filterHandler = (criteria: FieldValues) => {
70-
setFilterCriteria(criteria as FilterCriteria);
50+
const filterCriteria = criteria as FilterCriteria;
51+
setFilterCriteria(filterCriteria);
52+
53+
const queryString = serializeFilters(filterCriteria);
54+
const newUrl = queryString
55+
? `${window.location.pathname}?${queryString}`
56+
: window.location.pathname;
57+
58+
window.history.replaceState({}, '', newUrl);
7159
};
7260

7361
const stats = [
@@ -116,10 +104,6 @@ export const DashboardPage = () => {
116104
},
117105
];
118106

119-
function getFullName(intern: Intern): string {
120-
return `${intern.firstName.trim()} ${intern.lastName.trim()}`.toLowerCase();
121-
}
122-
123107
const duplicateInterns =
124108
internsWithStatus?.filter(
125109
(i1) =>
@@ -153,7 +137,11 @@ export const DashboardPage = () => {
153137

154138
{actionsOpen && <BoardActions internIds={selection} />}
155139

156-
<InternFilter submitHandler={filterHandler} disabled={showDuplicates} />
140+
<InternFilter
141+
submitHandler={filterHandler}
142+
disabled={showDuplicates}
143+
initialValues={filterCriteria}
144+
/>
157145

158146
<Grid item xs={12} md={5}>
159147
<div className={c.buttonsWrapper}>

0 commit comments

Comments
 (0)