From 8300eee39b1a86f927eb2cbbe57174f81d660c11 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Thu, 3 Oct 2024 12:49:53 +0300 Subject: [PATCH] VKT(Frontend): Public examiner listing with mock data for good and satisfactory level [deploy] --- .../vkt/public/i18n/fi-FI/public.json | 7 ++ .../PublicExaminerListing.tsx | 93 +++++++++++++++---- .../vkt/src/interfaces/publicExaminer.ts | 18 +++- .../vkt/src/redux/reducers/publicExaminer.ts | 62 +++++++++++++ .../vkt/src/redux/selectors/publicExaminer.ts | 24 +++++ .../packages/vkt/src/redux/store/index.ts | 2 + 6 files changed, 185 insertions(+), 21 deletions(-) create mode 100644 frontend/packages/vkt/src/redux/reducers/publicExaminer.ts create mode 100644 frontend/packages/vkt/src/redux/selectors/publicExaminer.ts diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index b5f06db4e..e2f7a9fa3 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -319,6 +319,13 @@ }, "title": "Tulevat tutkintotilaisuudet" }, + "publicExaminerListing": { + "examLanguage": { + "ALL": "suomi & ruotsi", + "FI": "suomi", + "SV": "ruotsi" + } + }, "logoutSuccessPage": { "heading": "Uloskirjautuminen onnnistui", "info": "Olet kirjautunut ulos. Suljethan vielä kaikki selainikkunat." diff --git a/frontend/packages/vkt/src/components/publicExaminerListing/PublicExaminerListing.tsx b/frontend/packages/vkt/src/components/publicExaminerListing/PublicExaminerListing.tsx index ed4a0adbe..7f1c8ce56 100644 --- a/frontend/packages/vkt/src/components/publicExaminerListing/PublicExaminerListing.tsx +++ b/frontend/packages/vkt/src/components/publicExaminerListing/PublicExaminerListing.tsx @@ -1,11 +1,26 @@ -import { Paper, TableCell, TableHead, TableRow } from '@mui/material'; -import { useState } from 'react'; -import { CustomTable, H2, Text } from 'shared/components'; +import { + Paper, + SelectChangeEvent, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; +import { Fragment } from 'react'; +import { CustomButtonLink, CustomTable, H2, Text } from 'shared/components'; +import { Color, Variant } from 'shared/enums'; import { useWindowProperties } from 'shared/hooks'; +import { DateUtils } from 'shared/utils'; import { LanguageFilter } from 'components/common/LanguageFilter'; +import { usePublicTranslation } from 'configs/i18n'; +import { useAppDispatch, useAppSelector } from 'configs/redux'; import { ExamLanguage } from 'enums/app'; import { PublicExaminer } from 'interfaces/publicExaminer'; +import { setPublicExaminerLanguageFilter } from 'redux/reducers/publicExaminer'; +import { + publicExaminerSelector, + selectFilteredPublicExaminers, +} from 'redux/selectors/publicExaminer'; const PublicExaminerListingHeader = () => { const { isPhone } = useWindowProperties(); @@ -25,36 +40,82 @@ const PublicExaminerListingHeader = () => { ); }; -const mockExaminerData: Array = []; - -const getRowDetails = ({ +const DesktopExaminerRow = ({ name, language, - municipality, + municipalities, examDates, -}: PublicExaminer) => { +}: Omit) => { // TODO Rendering for mobile users + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicExaminerListing', + }); + return ( - + {name} - {language} + {t('examLanguage.' + language)} - {municipality} + + {municipalities.length > 0 ? municipalities.join(', ') : ''} + - {examDates.length > 0 ? 'dipdap' : 'Ei määritelty'} + + {examDates.length > 0 + ? examDates.map((v, i) => ( + + {i > 0 ?
: undefined} + {DateUtils.formatOptionalDate(v)} +
+ )) + : 'Ei määritelty'} +
+
+ + + Ota yhteyttä + - dsadad
); }; +const getRowDetails = ({ + name, + language, + municipalities, + examDates, +}: PublicExaminer) => { + return ( + + ); +}; + export const PublicExaminerListing = () => { - const [languageFilter, setLanguageFilter] = useState(ExamLanguage.ALL); + // TODO Kick off API request & display content based on request status + const { languageFilter } = useAppSelector(publicExaminerSelector); + const filteredExaminers = useAppSelector(selectFilteredPublicExaminers); + const dispatch = useAppDispatch(); + + const handleLanguageFilterChange = (event: SelectChangeEvent) => { + dispatch( + setPublicExaminerLanguageFilter(event.target.value as ExamLanguage), + ); + }; return ( @@ -65,11 +126,11 @@ export const PublicExaminerListing = () => { setLanguageFilter(e.target.value as ExamLanguage)} + onChange={handleLanguageFilterChange} /> } /> diff --git a/frontend/packages/vkt/src/interfaces/publicExaminer.ts b/frontend/packages/vkt/src/interfaces/publicExaminer.ts index 73a527034..0d3c5cd19 100644 --- a/frontend/packages/vkt/src/interfaces/publicExaminer.ts +++ b/frontend/packages/vkt/src/interfaces/publicExaminer.ts @@ -1,11 +1,19 @@ -import { Dayjs } from "dayjs"; -import { WithId } from "shared/interfaces"; +import { Dayjs } from 'dayjs'; +import { WithId } from 'shared/interfaces'; -import { ExamLanguage } from "enums/app"; +import { ExamLanguage } from 'enums/app'; +import { APIResponseStatus } from 'shared/enums'; export interface PublicExaminer extends WithId { name: string; language: ExamLanguage; - municipality: Array; + // TODO Municipality could instead be something like { fi: 'Helsinki', sv: 'Helsingfors' } ? + municipalities: Array; examDates: Array; -} \ No newline at end of file +} + +export interface PublicExaminerState { + status: APIResponseStatus; + examiners: Array; + languageFilter: ExamLanguage; +} diff --git a/frontend/packages/vkt/src/redux/reducers/publicExaminer.ts b/frontend/packages/vkt/src/redux/reducers/publicExaminer.ts new file mode 100644 index 000000000..35d98e302 --- /dev/null +++ b/frontend/packages/vkt/src/redux/reducers/publicExaminer.ts @@ -0,0 +1,62 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import dayjs from 'dayjs'; +import { APIResponseStatus } from 'shared/enums'; + +import { ExamLanguage } from 'enums/app'; +import { PublicExaminerState } from 'interfaces/publicExaminer'; + +const initialState: PublicExaminerState = { + status: APIResponseStatus.Success, + examiners: [ + { + id: 1, + name: 'Eemeli Laine', + language: ExamLanguage.FI, + municipalities: ['Helsinki', 'Espoo', 'Vantaa', 'Kauniainen'], + examDates: [], + }, + { + id: 2, + name: 'Kerttu Virtanen', + language: ExamLanguage.SV, + municipalities: ['Vaasa'], + examDates: [], + }, + { + id: 3, + name: 'Aapo Mäkinen', + language: ExamLanguage.ALL, + municipalities: ['Tampere'], + examDates: [dayjs('2024-10-17')], + }, + { + id: 4, + name: 'Veera Salminen', + language: ExamLanguage.FI, + municipalities: ['Kajaani'], + examDates: [ + dayjs('2024-09-12'), + dayjs('2024-09-13'), + dayjs('2024-09-19'), + dayjs('2024-09-20'), + ], + }, + ], + languageFilter: ExamLanguage.ALL, +}; + +const publicExaminerSlice = createSlice({ + name: 'publicExaminer', + initialState, + reducers: { + setPublicExaminerLanguageFilter( + state, + action: PayloadAction, + ) { + state.languageFilter = action.payload; + }, + }, +}); + +export const publicExaminerReducer = publicExaminerSlice.reducer; +export const { setPublicExaminerLanguageFilter } = publicExaminerSlice.actions; diff --git a/frontend/packages/vkt/src/redux/selectors/publicExaminer.ts b/frontend/packages/vkt/src/redux/selectors/publicExaminer.ts new file mode 100644 index 000000000..0d0ba0bc3 --- /dev/null +++ b/frontend/packages/vkt/src/redux/selectors/publicExaminer.ts @@ -0,0 +1,24 @@ +import { createSelector } from '@reduxjs/toolkit'; + +import { RootState } from 'configs/redux'; +import { ExamLanguage } from 'enums/app'; +import { PublicExaminer, PublicExaminerState } from 'interfaces/publicExaminer'; + +export const publicExaminerSelector: ( + state: RootState, +) => PublicExaminerState = (state: RootState) => state.publicExaminer; + +export const selectFilteredPublicExaminers = createSelector( + (state: RootState) => state.publicExaminer.examiners, + (state: RootState) => state.publicExaminer.languageFilter, + (publicExaminers: Array, languageFilter: ExamLanguage) => { + if (languageFilter === ExamLanguage.ALL) { + return publicExaminers; + } else { + return publicExaminers.filter( + ({ language }) => + language === ExamLanguage.ALL || language === languageFilter, + ); + } + }, +); diff --git a/frontend/packages/vkt/src/redux/store/index.ts b/frontend/packages/vkt/src/redux/store/index.ts index 0ff0ae0b6..b7b6ff057 100644 --- a/frontend/packages/vkt/src/redux/store/index.ts +++ b/frontend/packages/vkt/src/redux/store/index.ts @@ -14,6 +14,7 @@ import { featureFlagsReducer } from 'redux/reducers/featureFlags'; import { publicEducationReducer } from 'redux/reducers/publicEducation'; import { publicEnrollmentReducer } from 'redux/reducers/publicEnrollment'; import { publicExamEventReducer } from 'redux/reducers/publicExamEvent'; +import { publicExaminerReducer } from 'redux/reducers/publicExaminer'; import { publicFileUploadReducer } from 'redux/reducers/publicFileUpload'; import { publicUserReducer } from 'redux/reducers/publicUser'; import rootSaga from 'redux/sagas/index'; @@ -38,6 +39,7 @@ const reducer = combineReducers({ featureFlags: featureFlagsReducer, publicFileUpload: publicFileUploadReducer, publicEducation: publicEducationReducer, + publicExaminer: publicExaminerReducer, }); const persistedReducer = persistReducer(persistConfig, reducer);