Skip to content

Commit

Permalink
VKT(Frontend): Public examiner listing with mock data for good and sa…
Browse files Browse the repository at this point in the history
…tisfactory level [deploy]
  • Loading branch information
pkoivisto committed Oct 7, 2024
1 parent 93ffe2a commit 8300eee
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 21 deletions.
7 changes: 7 additions & 0 deletions frontend/packages/vkt/public/i18n/fi-FI/public.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -25,36 +40,82 @@ const PublicExaminerListingHeader = () => {
);
};

const mockExaminerData: Array<PublicExaminer> = [];

const getRowDetails = ({
const DesktopExaminerRow = ({
name,
language,
municipality,
municipalities,
examDates,
}: PublicExaminer) => {
}: Omit<PublicExaminer, 'id'>) => {
// TODO Rendering for mobile users
const { t } = usePublicTranslation({
keyPrefix: 'vkt.component.publicExaminerListing',
});

return (
<TableRow>
<TableRow sx={{ verticalAlign: 'text-top' }}>
<TableCell>
<Text>{name}</Text>
</TableCell>
<TableCell>
<Text>{language}</Text>
<Text>{t('examLanguage.' + language)}</Text>
</TableCell>
<TableCell>
<Text>{municipality}</Text>
<Text>
{municipalities.length > 0 ? municipalities.join(', ') : ''}
</Text>
</TableCell>
<TableCell>
<Text>{examDates.length > 0 ? 'dipdap' : 'Ei määritelty'}</Text>
<Text>
{examDates.length > 0
? examDates.map((v, i) => (
<Fragment key={i}>
{i > 0 ? <br /> : undefined}
{DateUtils.formatOptionalDate(v)}
</Fragment>
))
: 'Ei määritelty'}
</Text>
</TableCell>
<TableCell>
<CustomButtonLink
color={Color.Secondary}
variant={Variant.Outlined}
to={''}
>
Ota yhteyttä
</CustomButtonLink>
</TableCell>
<TableCell>dsadad</TableCell>
</TableRow>
);
};

const getRowDetails = ({
name,
language,
municipalities,
examDates,
}: PublicExaminer) => {
return (
<DesktopExaminerRow
name={name}
language={language}
municipalities={municipalities}
examDates={examDates}
/>
);
};

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 (
<Paper elevation={3} className="public-examiner-listing">
Expand All @@ -65,11 +126,11 @@ export const PublicExaminerListing = () => {
</div>
<LanguageFilter
value={languageFilter}
onChange={(e) => setLanguageFilter(e.target.value as ExamLanguage)}
onChange={handleLanguageFilterChange}
/>
<CustomTable
className="table-layout-auto"
data={mockExaminerData}
data={filteredExaminers}
getRowDetails={getRowDetails}
header={<PublicExaminerListingHeader />}
/>
Expand Down
18 changes: 13 additions & 5 deletions frontend/packages/vkt/src/interfaces/publicExaminer.ts
Original file line number Diff line number Diff line change
@@ -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<string>;
// TODO Municipality could instead be something like { fi: 'Helsinki', sv: 'Helsingfors' } ?
municipalities: Array<string>;
examDates: Array<Dayjs>;
}
}

export interface PublicExaminerState {
status: APIResponseStatus;
examiners: Array<PublicExaminer>;
languageFilter: ExamLanguage;
}
62 changes: 62 additions & 0 deletions frontend/packages/vkt/src/redux/reducers/publicExaminer.ts
Original file line number Diff line number Diff line change
@@ -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<ExamLanguage>,
) {
state.languageFilter = action.payload;
},
},
});

export const publicExaminerReducer = publicExaminerSlice.reducer;
export const { setPublicExaminerLanguageFilter } = publicExaminerSlice.actions;
24 changes: 24 additions & 0 deletions frontend/packages/vkt/src/redux/selectors/publicExaminer.ts
Original file line number Diff line number Diff line change
@@ -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<PublicExaminer>, languageFilter: ExamLanguage) => {
if (languageFilter === ExamLanguage.ALL) {
return publicExaminers;
} else {
return publicExaminers.filter(
({ language }) =>
language === ExamLanguage.ALL || language === languageFilter,
);
}
},
);
2 changes: 2 additions & 0 deletions frontend/packages/vkt/src/redux/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -38,6 +39,7 @@ const reducer = combineReducers({
featureFlags: featureFlagsReducer,
publicFileUpload: publicFileUploadReducer,
publicEducation: publicEducationReducer,
publicExaminer: publicExaminerReducer,
});

const persistedReducer = persistReducer(persistConfig, reducer);
Expand Down

0 comments on commit 8300eee

Please sign in to comment.