Skip to content

Commit

Permalink
VKT(Frontend): ClerkExaminerListing language filters [deploy]
Browse files Browse the repository at this point in the history
  • Loading branch information
pkoivisto committed Nov 18, 2024
1 parent 1c97216 commit 9645463
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 33 deletions.
8 changes: 8 additions & 0 deletions frontend/packages/vkt/public/i18n/fi-FI/examiner.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@
"upcoming": "Tulevat"
}
},
"examinerFilter": {
"label": "Näytä seuraavien kielten tutkintosuoritusten vastaanottajat",
"options": {
"ALL": "Molemmat kielet",
"FI": "Suomi",
"SV": "Ruotsi"
}
},
"examinerHomepage": {
"heading": "Hyvän ja tyydyttävän taidon kielitutkinnot"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {
Divider,
SelectChangeEvent,
FormControl,
FormControlLabel,
FormLabel,
Radio,
RadioGroup,
TableCell,
TableHead,
TableRow,
Expand All @@ -9,18 +13,20 @@ import { Link } from 'react-router-dom';
import { CustomButtonLink, CustomTable, H2, Text } from 'shared/components';
import { Color, Variant } from 'shared/enums';

import { LanguageFilter } from 'components/common/LanguageFilter';
import {
useClerkTranslation,
useCommonTranslation,
useExaminerTranslation,
useKoodistoMunicipalitiesTranslation,
} from 'configs/i18n';
import { useAppDispatch, useAppSelector } from 'configs/redux';
import { AppRoutes, ExamLanguage } from 'enums/app';
import { ExaminerDetails } from 'interfaces/examinerDetails';
import { setExamEventLanguageFilter } from 'redux/reducers/clerkListExamEvent';
import { clerkListExamEventsSelector } from 'redux/selectors/clerkListExamEvent';
import { clerkListExaminerSelector } from 'redux/selectors/clerkListExaminer';
import { setClerkListExaminerFilters } from 'redux/reducers/clerkListExaminer';
import {
clerkListExaminerSelector,
selectFilteredExaminers,
} from 'redux/selectors/clerkListExaminer';
import { ExaminerUtils } from 'utils/examiner';

const ClerkExaminerListingHeader = () => {
Expand Down Expand Up @@ -49,7 +55,7 @@ const ExaminerListingRow = ({ examiner }: { examiner: ExaminerDetails }) => {
const translateCommon = useCommonTranslation();
const translateMunicipality = useKoodistoMunicipalitiesTranslation();

const examinerUrl = AppRoutes.ExaminerDetailsPage.replace(
const examinerUrl = AppRoutes.ExaminerHomePage.replace(
/:oid/,
`${examiner.oid}`,
);
Expand Down Expand Up @@ -99,30 +105,62 @@ const getRowDetails = (examiner: ExaminerDetails) => {
return <ExaminerListingRow examiner={examiner} />;
};

export const ClerkExaminerListing = () => {
const { t } = useClerkTranslation({
keyPrefix: 'vkt.component.clerkExaminerListing',
const ExaminerFilter = () => {
const { t } = useExaminerTranslation({
keyPrefix: 'vkt.component.examinerFilter',
});
const { examLanguage } = useAppSelector(clerkListExaminerSelector).filters;
const dispatch = useAppDispatch();

const { languageFilter } = useAppSelector(clerkListExamEventsSelector);
return (
<FormControl className="margin-top-lg" component="fieldset">
<FormLabel component="legend" className="heading-label">
{t('label')}:
</FormLabel>
<RadioGroup
data-testid="examiner-filter"
name="examiner-filter"
value={examLanguage}
onChange={(e) => {
dispatch(
setClerkListExaminerFilters({
examLanguage: e.target.value as ExamLanguage,
}),
);
}}
>
<div className="columns margin-left-sm">
{Object.entries(ExamLanguage).map(([key, language]) => {
return (
<FormControlLabel
key={key}
value={language}
checked={examLanguage === language}
label={t(`options.${key}`)}
control={<Radio />}
/>
);
})}
</div>
</RadioGroup>
</FormControl>
);
};

const handleLanguageFilterChange = (event: SelectChangeEvent) => {
dispatch(setExamEventLanguageFilter(event.target.value as ExamLanguage));
};
export const ClerkExaminerListing = () => {
const { t } = useClerkTranslation({
keyPrefix: 'vkt.component.clerkExaminerListing',
});

const { examiners } = useAppSelector(clerkListExaminerSelector);
const examiners = useAppSelector(selectFilteredExaminers);

return (
<>
<div className="clerk-homepage__grid-container__heading columns grow">
<H2>{t('title')}</H2>
</div>
<Divider />
<LanguageFilter
value={languageFilter}
onChange={handleLanguageFilterChange}
/>
<ExaminerFilter />
<CustomTable
className="table-layout-auto"
data={examiners}
Expand Down
6 changes: 6 additions & 0 deletions frontend/packages/vkt/src/interfaces/clerkListExaminer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { APIResponseStatus } from 'shared/enums';

import { ExamLanguage } from 'enums/app';
import { ExaminerDetails } from 'interfaces/examinerDetails';

export interface ClerkListExaminerFilters {
examLanguage: ExamLanguage;
}

export interface ClerkListExaminerState {
status: APIResponseStatus;
examiners: Array<ExaminerDetails>;
filters: ClerkListExaminerFilters;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useClerkTranslation } from 'configs/i18n';
import { useAppDispatch, useAppSelector } from 'configs/redux';
import { resetClerkExamEventOverview } from 'redux/reducers/clerkExamEventOverview';
import { loadExamEvents } from 'redux/reducers/clerkListExamEvent';
import { loadExaminers } from 'redux/reducers/clerkListExaminer';
import { loadClerkListExaminers } from 'redux/reducers/clerkListExaminer';
import { clerkListExamEventsSelector } from 'redux/selectors/clerkListExamEvent';
import { clerkListExaminerSelector } from 'redux/selectors/clerkListExaminer';

Expand Down Expand Up @@ -38,7 +38,7 @@ export const ClerkGoodAndSatisfactoryLevelPage: FC = () => {
}, [dispatch, examEventsStatus]);
useEffect(() => {
if (examinerListStatus === APIResponseStatus.NotStarted) {
dispatch(loadExaminers());
dispatch(loadClerkListExaminers());
}
}, [dispatch, examinerListStatus]);

Expand Down
32 changes: 26 additions & 6 deletions frontend/packages/vkt/src/redux/reducers/clerkListExaminer.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,51 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { APIResponseStatus } from 'shared/enums';

import { ClerkListExaminerState } from 'interfaces/clerkListExaminer';
import { ExamLanguage } from 'enums/app';
import {
ClerkListExaminerFilters,
ClerkListExaminerState,
} from 'interfaces/clerkListExaminer';
import { ExaminerDetails } from 'interfaces/examinerDetails';

const initialState: ClerkListExaminerState = {
status: APIResponseStatus.NotStarted,
examiners: [],
filters: {
examLanguage: ExamLanguage.ALL,
},
};

const clerkListExaminerSlice = createSlice({
name: 'clerkListExaminer',
initialState,
reducers: {
acceptExaminers(state, action: PayloadAction<Array<ExaminerDetails>>) {
acceptClerkListExaminers(
state,
action: PayloadAction<Array<ExaminerDetails>>,
) {
state.status = APIResponseStatus.Success;
state.examiners = action.payload;
},
loadExaminers(state) {
loadClerkListExaminers(state) {
state.status = APIResponseStatus.InProgress;
},
rejectExaminers(state) {
rejectClerkListExaminers(state) {
state.status = APIResponseStatus.Error;
},
setClerkListExaminerFilters(
state,
action: PayloadAction<ClerkListExaminerFilters>,
) {
state.filters = action.payload;
},
},
});

export const { acceptExaminers, loadExaminers, rejectExaminers } =
clerkListExaminerSlice.actions;
export const {
acceptClerkListExaminers,
loadClerkListExaminers,
rejectClerkListExaminers,
setClerkListExaminerFilters,
} = clerkListExaminerSlice.actions;
export const clerkListExaminerReducer = clerkListExaminerSlice.reducer;
12 changes: 6 additions & 6 deletions frontend/packages/vkt/src/redux/sagas/clerkListExaminer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { APIEndpoints } from 'enums/api';
import { ExaminerDetails } from 'interfaces/examinerDetails';
import { setAPIError } from 'redux/reducers/APIError';
import {
acceptExaminers,
loadExaminers,
rejectExaminers,
acceptClerkListExaminers,
loadClerkListExaminers,
rejectClerkListExaminers,
} from 'redux/reducers/clerkListExaminer';
import { NotifierUtils } from 'utils/notifier';

Expand All @@ -18,14 +18,14 @@ function* loadExaminersSaga() {
axiosInstance.get,
APIEndpoints.ClerkExaminer,
);
yield put(acceptExaminers(response.data));
yield put(acceptClerkListExaminers(response.data));
} catch (error) {
const errorMessage = NotifierUtils.getAPIErrorMessage(error as AxiosError);
yield put(setAPIError(errorMessage));
yield put(rejectExaminers());
yield put(rejectClerkListExaminers());
}
}

export function* watchListExaminers() {
yield takeLatest(loadExaminers.type, loadExaminersSaga);
yield takeLatest(loadClerkListExaminers.type, loadExaminersSaga);
}
28 changes: 27 additions & 1 deletion frontend/packages/vkt/src/redux/selectors/clerkListExaminer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
import { createSelector } from '@reduxjs/toolkit';

import { RootState } from 'configs/redux';
import { ClerkListExaminerState } from 'interfaces/clerkListExaminer';
import { ExamLanguage } from 'enums/app';
import {
ClerkListExaminerFilters,
ClerkListExaminerState,
} from 'interfaces/clerkListExaminer';
import { ExaminerDetails } from 'interfaces/examinerDetails';

export const clerkListExaminerSelector = (
state: RootState,
): ClerkListExaminerState => state.clerkListExaminer;

export const selectFilteredExaminers = createSelector(
(state: RootState) => state.clerkListExaminer.examiners,
(state: RootState) => state.clerkListExaminer.filters,
(
examiners: Array<ExaminerDetails>,
filters: ClerkListExaminerFilters,
): Array<ExaminerDetails> => {
const { examLanguage } = filters;

if (examLanguage === ExamLanguage.FI) {
return examiners.filter((e) => e.examLanguageFinnish);
} else if (examLanguage === ExamLanguage.SV) {
return examiners.filter((e) => e.examLanguageSwedish);
} else {
return examiners;
}
},
);

0 comments on commit 9645463

Please sign in to comment.