Skip to content

Commit

Permalink
Merge pull request #1207 from City-of-Helsinki/develop
Browse files Browse the repository at this point in the history
Release v2.0.30
  • Loading branch information
japauliina authored Nov 26, 2024
2 parents 094f0aa + 2f3418c commit 4d60b83
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 153 deletions.
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ ACCESSIBILITY_SENTENCE_API="https://www.hel.fi/palvelukarttaws/rest/v4"
SERVICEMAP_API="https://api.hel.fi/servicemap/"
SERVICEMAP_API_VERSION="v2"
EVENTS_API="https://api.hel.fi/linkedevents/v1"
RESERVATIONS_API="https://api.hel.fi/respa/v1"

RESERVATIONS_API="https://tilavaraus.hel.fi" # For production
# RESERVATIONS_API="https://tilavaraus.test.hel.ninja" # For test environment
# RESERVATIONS_API="https://tilavaraus.dev.hel.ninja" # For local development

FEEDBACK_URL="https://api.hel.fi/servicemap/open311/"
DIGITRANSIT_API="https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql"
# This is key for DIGITRANSIT API. There are separate urls and keys for prod (api.digitransit.fi) and dev (dev-api.digitransit.fi) digitransit apis. Developer should generate own
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
SERVICEMAP_API: https://api.hel.fi/servicemap/
SERVICEMAP_API_VERSION: "v2"
EVENTS_API: https://api.hel.fi/linkedevents/v1
RESERVATIONS_API: https://api.hel.fi/respa/v1
RESERVATIONS_API: https://tilavaraus.hel.fi
PRODUCTION_PREFIX: SM
DIGITRANSIT_API: https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql
DIGITRANSIT_API_KEY: a9219bfb875d4cc79b5f69123b57d0db
Expand Down
2 changes: 1 addition & 1 deletion server/dataFetcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export const fetchSelectedUnitData = (req, res, next) => {
store.dispatch(fetchSuccess(data.results));
response();
}
reservationsFetch({ unit: `tprek:${id}` }, null, reservationFetchEnd, fetchOnError, null, null, controller)
reservationsFetch(null, null, reservationFetchEnd, fetchOnError, null, id, controller);

} catch(e) {
console.log('Error in fetchSelectedUnitData', e.message);
Expand Down
33 changes: 26 additions & 7 deletions src/components/ListItems/ReservationItem/ReservationItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,37 @@ import React from 'react';
import PropTypes from 'prop-types';
import { EventAvailable } from '@mui/icons-material';
import SimpleListItem from '../SimpleListItem';
import useLocaleText from '../../../utils/useLocaleText';
import config from '../../../../config';
import { useSelector } from 'react-redux';
import { getLocale } from '../../../redux/selectors/user';

const getLocalizedText = (reservation, locale) => {
switch (locale) {
case 'fi':
return reservation.name_fi;
case 'en':
return reservation.name_en;
case 'sv':
return reservation.name_sv;
default:
return reservation.name_fi; // Fallback to Finnish
}
};

const ReservationItem = ({ reservation, intl, divider }) => {
const getLocaleText = useLocaleText();
const locale = useSelector(getLocale);
const localizedText = getLocalizedText(reservation, locale);

return (
<SimpleListItem
key={reservation.id}
key={reservation.pk}
className="reservationItem"
icon={<EventAvailable color="primary" />}
link
text={`${getLocaleText(reservation.name)} ${intl.formatMessage({ id: 'opens.new.tab' })}`}
text={`${localizedText} ${intl.formatMessage({ id: 'opens.new.tab' })}`}
divider={divider}
handleItemClick={() => {
window.open(`https://varaamo.hel.fi/resources/${reservation.id}`);
window.open(`${config.reservationsAPI.root}/${locale}/reservation-unit/${reservation.pk}`);
}}
/>
);
Expand All @@ -24,8 +41,10 @@ const ReservationItem = ({ reservation, intl, divider }) => {
ReservationItem.propTypes = {
intl: PropTypes.objectOf(PropTypes.any).isRequired,
reservation: PropTypes.shape({
id: PropTypes.string,
name: PropTypes.objectOf(PropTypes.any),
pk: PropTypes.number,
name_fi: PropTypes.string,
name_en: PropTypes.string,
name_sv: PropTypes.string,
}).isRequired,
divider: PropTypes.bool,
};
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default {
'area.neighborhood.title': 'Choose neighbourhood',
'area.postcode_area.title': 'Choose postal code',
'area.major_district.title': 'Choose major district',
'area.service.filter': 'Filtering of services for areas',
'area.statisticalDistrict.info': 'First, select a population data area, and then you can browse the area\'s services',
'area.statisticalDistrict.title': 'Select a population data area',
'area.statisticalDistrict.section': 'Cropping: {text}',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default {
'area.neighborhood.title': 'Valitse kaupunginosa',
'area.postcode_area.title': 'Valitse postinumero',
'area.major_district.title': 'Valitse suurpiiri',
'area.service.filter': 'Palvelujen suodatus',
'area.statisticalDistrict.info': 'Valitse ensin väestötietoalue, jonka jälkeen voit selata alueen palveluita',
'area.statisticalDistrict.label': '{count} henkilöä, {percent}% alueen koko väestöstä',
'area.statisticalDistrict.label.total': '{count} henkilöä',
Expand Down
1 change: 1 addition & 0 deletions src/i18n/sv.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export default {
'area.neighborhood.title': 'Välj stadsdel',
'area.postcode_area.title': 'Välj postnummer',
'area.major_district.title': 'Välj stordistrikt',
'area.service.filter': 'Filtrering av geografiska tjänster',
'area.statisticalDistrict.info': 'Välj först befolkningsdataområdet, varefter du kan bläddra bland regionens tjänster',
'area.statisticalDistrict.title': 'Välj befolkningsdataområde',
'area.statisticalDistrict.section': 'Beskärning: {text}',
Expand Down
43 changes: 13 additions & 30 deletions src/redux/actions/selectedUnitReservations.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,31 @@ import { reservations } from './fetchDataActions';
import { reservationsFetch } from '../../utils/fetch';

const {
isFetching, fetchSuccess, fetchMoreSuccess, fetchError, fetchProgressUpdate,
isFetching, fetchSuccess, fetchError
} = reservations;

export const fetchReservations = (id, pageSize, all = false) => async (dispatch, getState) => {
const { selectedUnit } = getState();
const { reservations } = selectedUnit;
const previousFetch = reservations.previousSearch;
if (previousFetch) {
const parts = previousFetch.split('-');
if (parts[0] === id && parts[1] === 'all') {
return;
}
}
export const fetchReservations = (id) => async (dispatch, getState) => {

const onStart = () => {
dispatch(isFetching(`${id}-${all ? 'all' : 'partial'}`));
dispatch(isFetching(id));
};

const onSuccess = (data) => {
if (data && data.length) {
dispatch(fetchSuccess(data));
return;
}
dispatch(fetchProgressUpdate(data.results.length, data.count, data.next));
dispatch(fetchSuccess(data.results, { count: data.count, next: data.next }));
};
const onError = e => dispatch(fetchError(e.message));
const onNext = all ? (resultTotal, response) => {
dispatch(fetchProgressUpdate(resultTotal.length, response.count));
} : null;

// Fetch data
reservationsFetch({ unit: `tprek:${id}`, page_size: pageSize || 5 }, onStart, onSuccess, onError, onNext);
};


export const fetchAdditionalReservations = next => async (dispatch) => {
// fetch additional data that is added to previous data
const onStart = () => dispatch(isFetching());
const onSuccess = (data) => {
dispatch(fetchMoreSuccess(data.results, { count: data.count, next: data.next }));
const onError = e => {
console.error(e); // Log the error
dispatch(fetchError(e.message));
};
const onError = e => dispatch(fetchError(e.message));

// Fetch data
reservationsFetch(null, onStart, onSuccess, onError, null, null, null, next);
try {
await reservationsFetch(null, onStart, onSuccess, onError, null, id, null, null, null);
} catch (e) {
onError(e);
}
};
8 changes: 3 additions & 5 deletions src/utils/fetch/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ export const APIHandlers = {
envName: config.serviceMapAPI.id,
},
reservations: {
url: `${config.reservationsAPI.root}/resource/`,
options: {
page_size: 5,
},
envName: config.serviceMapAPI.id,
url: id => `${config.reservationsAPI.root}/v1/palvelukartta/reservation-units/${id}`,
options: {},
envName: config.reservationsAPI.id,
},
search: {
url: `${config.serviceMapAPI.root}${config.serviceMapAPI.version}/search/`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Checkbox, List, Typography } from '@mui/material';
import PropTypes from 'prop-types';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, {
useCallback, useEffect, useMemo, useRef, useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from 'react-intl';
import { UnitItem } from '../../../../components';
import {
addSelectedDistrictService,
Expand All @@ -13,7 +16,7 @@ import {
selectSelectedDistrictServices,
} from '../../../../redux/selectors/district';
import { getLocale } from '../../../../redux/selectors/user';
import { uppercaseFirst } from '../../../../utils';
import { keyboardHandler, uppercaseFirst } from '../../../../utils';
import { orderUnits } from '../../../../utils/orderUnits';
import useLocaleText from '../../../../utils/useLocaleText';
import {
Expand All @@ -24,6 +27,7 @@ import {
StyledUnitList,
StyledUnitListArea,
} from '../styled/styled';
import ServiceFilterContainer from '../ServiceFilterContainer/ServiceFilterContainer';

// Custom uncontrolled checkbox that allows default value
const UnitCheckbox = ({
Expand Down Expand Up @@ -56,7 +60,16 @@ const GeographicalUnitList = ({ initialOpenItems }) => {
const locale = useSelector(getLocale);
const [serviceList, setServiceList] = useState([]);
const [initialCheckedItems] = useState(selectedServices);

const inputRef = useRef();
const { formatMessage } = useIntl();
const [filterValue, setFilterValue] = useState('');
const title = formatMessage({ id: 'area.service.filter' });

const handlefilterButtonClick = () => {
if (inputRef) {
setFilterValue(inputRef.current.value);
}
};

const handleUnitCheckboxChange = useCallback((event, id) => {
if (event.target.checked) {
Expand Down Expand Up @@ -112,18 +125,37 @@ const GeographicalUnitList = ({ initialOpenItems }) => {
if (emptyCategories.length) {
dispatch(removeSelectedDistrictService(emptyCategories));
}

// Use filter
if (filterValue) {
const filteredServiceList = serviceList.filter((category) => {
const name = getLocaleText(category.name);
return name.toLowerCase().includes(filterValue.toLowerCase());
});
setServiceList(filteredServiceList);
return;
}

setServiceList(serviceList);
};


useEffect(() => {
createServiceCategories();
}, [filteredSubdistrictUnits]);

}, [filteredSubdistrictUnits, filterValue]);

// Render list of units for neighborhood and postcode-area subdistricts
const renderUnitList = useMemo(() => (
<StyledUnitListArea>
<ServiceFilterContainer
title={title}
inputRef={inputRef}
keyboardHandler={keyboardHandler}
handlefilterButtonClick={handlefilterButtonClick}
filterValue={filterValue}
setFilterValue={setFilterValue}
formatMessage={formatMessage}
/>
<List disablePadding>
{serviceList.map(category => (
<StyledListItem
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import { useTheme } from '@mui/styles';
import {
IconButton, Typography,
} from '@mui/material';
import { Clear } from '@mui/icons-material';
import { FormattedMessage } from 'react-intl';
import {
StyledServiceFilterContainer,
StyledServiceFilterText,
StyledRowContainer,
StyledServiceFilter,
StyledServiceFilterButton,
} from '../styled/styled';
import { createServiceFilterStyles } from '../../serviceFilterStyles';

const ServiceFilterContainer = ({
title,
inputRef,
keyboardHandler,
handlefilterButtonClick,
filterValue,
setFilterValue,
formatMessage,
}) => {
const theme = useTheme();
const {
serviceFilterInputClass,
serviceFilterButtonLabelClass,
serviceFilterButtonFocusClass,
} = createServiceFilterStyles(theme);

return (
<StyledServiceFilterContainer>
{typeof title === 'string' && (
<StyledServiceFilterText id="ServiceListTitle" variant="body2">
{title}
</StyledServiceFilterText>
)}
<StyledRowContainer>
<StyledServiceFilter
inputRef={inputRef}
inputProps={{
className: serviceFilterInputClass,
'aria-labelledby': 'ServiceListTitle',
}}
type="text"
onKeyPress={keyboardHandler(() => handlefilterButtonClick(), ['enter'])}
endAdornment={
filterValue ? (
<IconButton
aria-label={formatMessage({ id: 'search.cancelText' })}
onClick={() => {
inputRef.current.value = '';
setFilterValue('');
}}
>
<Clear />
</IconButton>
) : null
}
/>
<StyledServiceFilterButton
id="ServiceListFilterButton"
aria-label={formatMessage({ id: 'area.statisticalDistrict.service.filter.button.aria' })}
disableRipple
disableFocusRipple
classes={{
label: serviceFilterButtonLabelClass,
focusVisible: serviceFilterButtonFocusClass,
}}
onClick={handlefilterButtonClick}
color="secondary"
variant="contained"
>
<Typography variant="caption" color="inherit">
<FormattedMessage id="area.statisticalDistrict.service.filter.button" />
</Typography>
</StyledServiceFilterButton>
</StyledRowContainer>
</StyledServiceFilterContainer>
);
};

export default ServiceFilterContainer;
3 changes: 3 additions & 0 deletions src/views/AreaView/components/ServiceFilterContainer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ServiceFilterContainer from './ServiceFilterContainer';

export default ServiceFilterContainer;
Loading

0 comments on commit 4d60b83

Please sign in to comment.