From b8d37fa3fd7e2cdf5b0acf7b7a060f037f14e762 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Thu, 21 Mar 2019 15:20:17 +0200 Subject: [PATCH 01/55] moving component to folder, cleanup --- app/shared/resource-card/ResourceCard.js | 25 ++++++++++++++++++- .../button/ResourceCardButton.js | 17 +++++++++++++ .../button/ResourceCardButton.spec.js | 0 app/shared/resource-card/button/index.js | 3 +++ .../{ => label}/ResourceAvailability.js | 0 .../{ => label}/ResourceAvailability.spec.js | 0 app/shared/resource-card/label/index.js | 3 +++ ...r.spec.js => resourceCardSelector.spec.js} | 0 8 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 app/shared/resource-card/button/ResourceCardButton.js create mode 100644 app/shared/resource-card/button/ResourceCardButton.spec.js create mode 100644 app/shared/resource-card/button/index.js rename app/shared/resource-card/{ => label}/ResourceAvailability.js (100%) rename app/shared/resource-card/{ => label}/ResourceAvailability.spec.js (100%) create mode 100644 app/shared/resource-card/label/index.js rename app/shared/resource-card/{resourceListItemSelector.spec.js => resourceCardSelector.spec.js} (100%) diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js index e82b39351..98231b845 100644 --- a/app/shared/resource-card/ResourceCard.js +++ b/app/shared/resource-card/ResourceCard.js @@ -9,7 +9,9 @@ import iconHome from 'hel-icons/dist/shapes/home.svg'; import iconMapMarker from 'hel-icons/dist/shapes/map-marker.svg'; import iconTicket from 'hel-icons/dist/shapes/ticket.svg'; import iconUser from 'hel-icons/dist/shapes/user-o.svg'; +import iconHeart from 'hel-icons/dist/shapes/heart-o.svg'; +import iconHeartWhite from 'assets/icons/heart-white.svg'; import UnpublishedLabel from 'shared/label/Unpublished'; import { injectT } from 'i18n'; import iconMap from 'assets/icons/map.svg'; @@ -146,7 +148,11 @@ class ResourceCard extends Component {
- {resource.type.name} + {resource.type.name} {unit.streetAddress} @@ -174,6 +180,23 @@ class ResourceCard extends Component { + + +
+ + {resource.type.name} + +
+
); diff --git a/app/shared/resource-card/button/ResourceCardButton.js b/app/shared/resource-card/button/ResourceCardButton.js new file mode 100644 index 000000000..9968bb7e2 --- /dev/null +++ b/app/shared/resource-card/button/ResourceCardButton.js @@ -0,0 +1,17 @@ +import React from 'react'; +import Button from 'react-bootstrap/lib/Button'; + +export default function ResourceCardIcon({ className, }) { + return ( + + ); +} diff --git a/app/shared/resource-card/button/ResourceCardButton.spec.js b/app/shared/resource-card/button/ResourceCardButton.spec.js new file mode 100644 index 000000000..e69de29bb diff --git a/app/shared/resource-card/button/index.js b/app/shared/resource-card/button/index.js new file mode 100644 index 000000000..a506f73a2 --- /dev/null +++ b/app/shared/resource-card/button/index.js @@ -0,0 +1,3 @@ +import ResourceCardIcon from './ResourceCardIcon'; + +export default ResourceCardIcon; diff --git a/app/shared/resource-card/ResourceAvailability.js b/app/shared/resource-card/label/ResourceAvailability.js similarity index 100% rename from app/shared/resource-card/ResourceAvailability.js rename to app/shared/resource-card/label/ResourceAvailability.js diff --git a/app/shared/resource-card/ResourceAvailability.spec.js b/app/shared/resource-card/label/ResourceAvailability.spec.js similarity index 100% rename from app/shared/resource-card/ResourceAvailability.spec.js rename to app/shared/resource-card/label/ResourceAvailability.spec.js diff --git a/app/shared/resource-card/label/index.js b/app/shared/resource-card/label/index.js new file mode 100644 index 000000000..781b55cfd --- /dev/null +++ b/app/shared/resource-card/label/index.js @@ -0,0 +1,3 @@ +import ResourceAvailability from './ResourceAvailability'; + +export default ResourceAvailability; diff --git a/app/shared/resource-card/resourceListItemSelector.spec.js b/app/shared/resource-card/resourceCardSelector.spec.js similarity index 100% rename from app/shared/resource-card/resourceListItemSelector.spec.js rename to app/shared/resource-card/resourceCardSelector.spec.js From a3de15cbf92a0b83918cadaa3955e854e9e7443a Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Fri, 22 Mar 2019 12:33:41 +0200 Subject: [PATCH 02/55] rename component to button --- app/shared/resource-card/ResourceCard.js | 2 +- .../button/ResourceCardButton.js | 23 ++++++++++++++----- app/shared/resource-card/button/index.js | 4 ++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js index 98231b845..fb68758f9 100644 --- a/app/shared/resource-card/ResourceCard.js +++ b/app/shared/resource-card/ResourceCard.js @@ -18,7 +18,7 @@ import iconMap from 'assets/icons/map.svg'; import BackgroundImage from 'shared/background-image'; import { getMainImage } from 'utils/imageUtils'; import { getHourlyPrice, getResourcePageUrlComponents } from 'utils/resourceUtils'; -import ResourceAvailability from './ResourceAvailability'; +import ResourceAvailability from './label/ResourceAvailability'; class ResourceCard extends Component { handleSearchByType = () => { diff --git a/app/shared/resource-card/button/ResourceCardButton.js b/app/shared/resource-card/button/ResourceCardButton.js index 9968bb7e2..25658819b 100644 --- a/app/shared/resource-card/button/ResourceCardButton.js +++ b/app/shared/resource-card/button/ResourceCardButton.js @@ -1,17 +1,28 @@ import React from 'react'; import Button from 'react-bootstrap/lib/Button'; +import PropTypes from 'prop-types'; -export default function ResourceCardIcon({ className, }) { +function ResourceCardIcon({ + className, alt, icon, label, labelClassname, onClick +}) { return ( - ); } + +ResourceCardIcon.propTypes = { + className: PropTypes.string, + alt: PropTypes.string, + +}; + +export default ResourceCardIcon; diff --git a/app/shared/resource-card/button/index.js b/app/shared/resource-card/button/index.js index a506f73a2..f1713b7bb 100644 --- a/app/shared/resource-card/button/index.js +++ b/app/shared/resource-card/button/index.js @@ -1,3 +1,3 @@ -import ResourceCardIcon from './ResourceCardIcon'; +import ResourceCardButton from './ResourceCardButton'; -export default ResourceCardIcon; +export default ResourceCardButton; From 14582c08796602091a64cb87f79731ba57635277 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Fri, 22 Mar 2019 16:28:31 +0200 Subject: [PATCH 03/55] Refactor ResourceCard with reuseable cell, add favorite icon --- app/shared/resource-card/ResourceCard.js | 164 ++++++++---------- .../resource-card/ResourceCardContainer.js | 13 +- app/shared/resource-card/_resource-card.scss | 54 ++++-- .../button/ResourceCardButton.js | 28 --- app/shared/resource-card/button/index.js | 3 - .../info/ResourceCard\bInfoCell.spec.js" | 0 .../info/ResourceCardInfoCell.js | 29 ++++ app/shared/resource-card/info/index.js | 3 + 8 files changed, 149 insertions(+), 145 deletions(-) delete mode 100644 app/shared/resource-card/button/ResourceCardButton.js delete mode 100644 app/shared/resource-card/button/index.js rename app/shared/resource-card/button/ResourceCardButton.spec.js => "app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" (100%) create mode 100644 app/shared/resource-card/info/ResourceCardInfoCell.js create mode 100644 app/shared/resource-card/info/index.js diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js index fb68758f9..19a1e01aa 100644 --- a/app/shared/resource-card/ResourceCard.js +++ b/app/shared/resource-card/ResourceCard.js @@ -2,9 +2,8 @@ import classnames from 'classnames'; import round from 'lodash/round'; import PropTypes from 'prop-types'; import queryString from 'query-string'; -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { Link } from 'react-router-dom'; -import Col from 'react-bootstrap/lib/Col'; import iconHome from 'hel-icons/dist/shapes/home.svg'; import iconMapMarker from 'hel-icons/dist/shapes/map-marker.svg'; import iconTicket from 'hel-icons/dist/shapes/ticket.svg'; @@ -18,7 +17,9 @@ import iconMap from 'assets/icons/map.svg'; import BackgroundImage from 'shared/background-image'; import { getMainImage } from 'utils/imageUtils'; import { getHourlyPrice, getResourcePageUrlComponents } from 'utils/resourceUtils'; -import ResourceAvailability from './label/ResourceAvailability'; +import ResourceAvailability from './label'; +import ResourceCardInfoCell from './info'; + class ResourceCard extends Component { handleSearchByType = () => { @@ -50,6 +51,10 @@ class ResourceCard extends Component { history.replace({ pathname, search, state: { scrollTop } }); }; + toggleFavourite() { + + } + renderDistance(distance) { const km = distance / 1000; let formatedDistance = round(km); @@ -61,7 +66,7 @@ class ResourceCard extends Component { render() { const { - date, resource, t, unit + date, resource, t, unit, actions: { favoriteResource, unfavoriteResource } } = this.props; const { pathname, query } = getResourcePageUrlComponents(resource, date); const linkTo = { @@ -99,104 +104,72 @@ class ResourceCard extends Component {
{resource.description}
+
- - - {resource.type.name} - - {resource.type ? resource.type.name : '\u00A0'} - - - - - - {resource.peopleCapacity} - - {t('ResourceCard.peopleCapacity', { people: resource.peopleCapacity })} - - - - -
- {resource.type.name} - - {getHourlyPrice(t, resource) || '\u00A0'} - -
- - -
- {resource.type.name} - + + + {resource.type ? resource.type.name : '\u00A0'} + + + + + + {t('ResourceCard.peopleCapacity', { people: resource.peopleCapacity })} + + + + + + {getHourlyPrice(t, resource) || '\u00A0'} + + + + + + {unit.streetAddress} - + {unit.addressZip} {' '} {unit.municipality} -
- - - - {resource.type.name} - - {resource.distance ? this.renderDistance(resource.distance) : '\u00A0'} - - - - - -
- - {resource.type.name} - -
- + + + + + + {resource.distance ? this.renderDistance(resource.distance) : '\u00A0'} + + + + unfavoriteResource(resource.id) + : () => favoriteResource(resource.id) + } + />
); @@ -211,6 +184,7 @@ ResourceCard.propTypes = { stacked: PropTypes.bool, t: PropTypes.func.isRequired, unit: PropTypes.object.isRequired, + actions: PropTypes.object, }; export default injectT(ResourceCard); diff --git a/app/shared/resource-card/ResourceCardContainer.js b/app/shared/resource-card/ResourceCardContainer.js index eb50c38f8..b2b39e98f 100644 --- a/app/shared/resource-card/ResourceCardContainer.js +++ b/app/shared/resource-card/ResourceCardContainer.js @@ -1,6 +1,17 @@ import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; import resourceCardSelector from './resourceCardSelector'; import ResourceCard from './ResourceCard'; +import { favoriteResource, unfavoriteResource } from 'actions/resourceActions'; -export default connect(resourceCardSelector)(ResourceCard); +function mapDispatchToProps(dispatch) { + const actionCreators = { + favoriteResource, + unfavoriteResource, + }; + + return { actions: bindActionCreators(actionCreators, dispatch) }; +} + +export default connect(resourceCardSelector, mapDispatchToProps)(ResourceCard); diff --git a/app/shared/resource-card/_resource-card.scss b/app/shared/resource-card/_resource-card.scss index c6ead5d83..a22af2d69 100644 --- a/app/shared/resource-card/_resource-card.scss +++ b/app/shared/resource-card/_resource-card.scss @@ -1,6 +1,10 @@ $card-border-color: #d6d6d6; +$image-items-margin: 5px; +$resourceCardPadding: 15px; +$cellWidth: 33.33%; +$cellHeight: 50%; + .app-ResourceCard { - $image-items-margin: 5px; margin: 20px 0; background-color: white; display: flow-root; @@ -45,7 +49,7 @@ $card-border-color: #d6d6d6; } &__content { - padding: 15px; + padding: $resourceCardPadding; @media (min-width: $screen-md-min) { flex: 1 2 40%; overflow: hidden; @@ -93,25 +97,39 @@ $card-border-color: #d6d6d6; } &__info { - font-size: 1.2rem; - font-weight: bold; - text-align: center; - &-link, - &-detail { - display: inline-block; - &-capitalize { + padding: $resourceCardPadding; + display: flex; + flex-wrap: wrap; + + &-cell { + border: none; + background: transparent; + display: inline-flex; + flex-direction: column; + width: $cellWidth; + height: $cellHeight; + align-items: center; + &:hover, + &:focus { + outline: none; + &:active { + outline: none; + } + box-shadow: none; + } + + &__icon { + width: $line-height-computed*1.2; + } + + span { + font-size: 1.2rem; + font-weight: bold; + text-align: center; text-transform: capitalize; } } - > div { - padding-top: 15px; - } - &-label { - display: block; - } - &-icon { - width: $line-height-computed*1.2; - } + @media (min-width: $screen-xs-min) { display: inline-block; width: 100%; diff --git a/app/shared/resource-card/button/ResourceCardButton.js b/app/shared/resource-card/button/ResourceCardButton.js deleted file mode 100644 index 25658819b..000000000 --- a/app/shared/resource-card/button/ResourceCardButton.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import Button from 'react-bootstrap/lib/Button'; -import PropTypes from 'prop-types'; - -function ResourceCardIcon({ - className, alt, icon, label, labelClassname, onClick -}) { - return ( - - ); -} - -ResourceCardIcon.propTypes = { - className: PropTypes.string, - alt: PropTypes.string, - -}; - -export default ResourceCardIcon; diff --git a/app/shared/resource-card/button/index.js b/app/shared/resource-card/button/index.js deleted file mode 100644 index f1713b7bb..000000000 --- a/app/shared/resource-card/button/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import ResourceCardButton from './ResourceCardButton'; - -export default ResourceCardButton; diff --git a/app/shared/resource-card/button/ResourceCardButton.spec.js "b/app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" similarity index 100% rename from app/shared/resource-card/button/ResourceCardButton.spec.js rename to "app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" diff --git a/app/shared/resource-card/info/ResourceCardInfoCell.js b/app/shared/resource-card/info/ResourceCardInfoCell.js new file mode 100644 index 000000000..bae87a8d1 --- /dev/null +++ b/app/shared/resource-card/info/ResourceCardInfoCell.js @@ -0,0 +1,29 @@ +import React from 'react'; +import Button from 'react-bootstrap/lib/Button'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; + +function ResourceCardInfoCell({ + className, alt, icon, onClick, children +}) { + return ( + + ); +} + +ResourceCardInfoCell.propTypes = { + className: PropTypes.string, + alt: PropTypes.string, + children: PropTypes.element, + icon: PropTypes.string, + onClick: PropTypes.func, +}; + +export default ResourceCardInfoCell; diff --git a/app/shared/resource-card/info/index.js b/app/shared/resource-card/info/index.js new file mode 100644 index 000000000..618e2558c --- /dev/null +++ b/app/shared/resource-card/info/index.js @@ -0,0 +1,3 @@ +import ResourceCardInfoCell from './ResourceCardInfoCell'; + +export default ResourceCardInfoCell; From a05665bb8c5b6ade3c3626365f64cb00add493f5 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Fri, 22 Mar 2019 17:14:17 +0200 Subject: [PATCH 04/55] add unit test for fav and unfav func --- app/shared/resource-card/ResourceCard.spec.js | 69 ++++++++++++++++--- app/utils/fixtures/Resource.js | 4 +- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/app/shared/resource-card/ResourceCard.spec.js b/app/shared/resource-card/ResourceCard.spec.js index 5f09bc6c0..22669586d 100644 --- a/app/shared/resource-card/ResourceCard.spec.js +++ b/app/shared/resource-card/ResourceCard.spec.js @@ -2,6 +2,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import Immutable from 'seamless-immutable'; import simple from 'simple-mock'; +import iconHeart from 'hel-icons/dist/shapes/heart-o.svg'; import BackgroundImage from 'shared/background-image'; import Image from 'utils/fixtures/Image'; @@ -9,9 +10,11 @@ import Resource from 'utils/fixtures/Resource'; import Unit from 'utils/fixtures/Unit'; import { getResourcePageUrlComponents } from 'utils/resourceUtils'; import { shallowWithIntl } from 'utils/testUtils'; -import ResourceAvailability from './ResourceAvailability'; +import ResourceAvailability from './label/ResourceAvailability'; import ResourceCard from './ResourceCard'; import UnpublishedLabel from 'shared/label/Unpublished'; +import ResourceCardInfoCell from './info'; +import iconHeartWhite from 'assets/icons/heart-white.svg'; describe('shared/resource-card/ResourceCard', () => { function getResource(extra) { @@ -44,6 +47,10 @@ describe('shared/resource-card/ResourceCard', () => { }; const defaultProps = { + actions: { + favoriteResource: jest.fn(), + unfavoriteResource: jest.fn(), + }, history, date: '2015-10-10', isLoggedIn: false, @@ -98,6 +105,59 @@ describe('shared/resource-card/ResourceCard', () => { }); }); + describe('info box', () => { + test('render with 6 ResourceCardInfoCell cells', () => { + const info = getWrapper().find('.app-ResourceCard__info'); + const cells = info.find(ResourceCardInfoCell); + expect(cells.length).toEqual(6); + }); + + test('render with first ResourceCardInfoCell', () => { + const info = getWrapper().find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell).first(); + + expect(cell.prop('alt')).toEqual(defaultProps.resource.type.name); + expect(cell.prop('icon')).toBeDefined(); + expect(cell.prop('onClick')).toBeDefined(); + }); + + test('render with favorite icon as default', () => { + const info = getWrapper().find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell).last(); + + expect(cell.prop('alt')).toEqual(defaultProps.resource.type.name); + expect(cell.prop('icon')).toEqual(iconHeart); + expect(cell.prop('onClick')).toBeDefined(); + }); + + test('render with unfavorite icon when isFavorite is true', () => { + const info = getWrapper({ + resource: getResource({ isFavorite: true }) + }).find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell).last(); + + expect(cell.prop('alt')).toEqual(defaultProps.resource.type.name); + expect(cell.prop('icon')).toEqual(iconHeartWhite); + expect(cell.prop('onClick')).toBeDefined(); + }); + + test('invoke favorite func when favorite icon is clicked as default', () => { + const info = getWrapper().find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell).last(); + cell.simulate('click'); + expect(defaultProps.actions.favoriteResource).toHaveBeenCalledTimes(1); + }); + + test('invoke set unfavorite func when favorite icon is clicked', () => { + const info = getWrapper({ + resource: getResource({ isFavorite: true }) + }).find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell).last(); + cell.simulate('click'); + expect(defaultProps.actions.unfavoriteResource).toHaveBeenCalledTimes(1); + }); + }); + describe('people capacity', () => { test('renders people capacity', () => { const peopleCapacity = getWrapper().find('.app-ResourceCard__peopleCapacity'); @@ -215,13 +275,6 @@ describe('shared/resource-card/ResourceCard', () => { expect(zipAddress.html()).toContain(defaultProps.unit.municipality); }); - test('renders an anchor that calls handleSearchByType on click', () => { - const wrapper = getWrapper(); - const typeAnchor = wrapper.find('.app-ResourceCard__info-link-capitalize').filter('a'); - expect(typeAnchor).toHaveLength(1); - expect(typeAnchor.prop('onClick')).toBe(wrapper.instance().handleSearchByType); - }); - test('renders an anchor that calls handleSearchByUnitName on click', () => { const wrapper = getWrapper(); const unitAnchor = wrapper.find('.app-ResourceCard__unit-name-link'); diff --git a/app/utils/fixtures/Resource.js b/app/utils/fixtures/Resource.js index 9b5c556e5..dc5d00046 100644 --- a/app/utils/fixtures/Resource.js +++ b/app/utils/fixtures/Resource.js @@ -13,6 +13,6 @@ const Resource = new Factory() .attr('reservable', true) .attr('reservableAfter', null) .attr('supportedReservationExtraFields', []) - .attr('userPermissions', { isAdmin: false, canMakeReservations: true }); - + .attr('userPermissions', { isAdmin: false, canMakeReservations: true }) + .attr('isFavorite', false); export default Resource; From a6663decee279c6e09a2e113d6c542eec6c3608e Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Mon, 25 Mar 2019 10:18:45 +0200 Subject: [PATCH 05/55] add unit test, fix Jest watch to not watch node_modules by default --- app/shared/resource-card/ResourceCard.js | 4 -- .../info/ResourceCard\bInfoCell.spec.js" | 64 +++++++++++++++++++ jest.config.js | 5 ++ 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js index 19a1e01aa..f525b9bc2 100644 --- a/app/shared/resource-card/ResourceCard.js +++ b/app/shared/resource-card/ResourceCard.js @@ -51,10 +51,6 @@ class ResourceCard extends Component { history.replace({ pathname, search, state: { scrollTop } }); }; - toggleFavourite() { - - } - renderDistance(distance) { const km = distance / 1000; let formatedDistance = round(km); diff --git "a/app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" "b/app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" index e69de29bb..d271c5c18 100644 --- "a/app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" +++ "b/app/shared/resource-card/info/ResourceCard\bInfoCell.spec.js" @@ -0,0 +1,64 @@ +import { shallow } from 'enzyme'; +import React from 'react'; + +import ResourceCardInfoCell from './ResourceCardInfoCell'; +import iconMap from 'assets/icons/map.svg'; + +describe('/shared/resource-card/info/ResourceCardInfoCell', () => { + const defaultProps = { + className: 'app-ResourceCard__info-cell', + alt: 'foo', + icon: 'bar', + onClick: () => {} + }; + + function getWrapper(props) { + return shallow(); + } + + test('render normally', () => { + const wrapper = getWrapper(); + expect(wrapper).toHaveLength(1); + expect(wrapper).toBeDefined(); + }); + + test('contains default className, joined with passed className prop', () => { + const wrapper = getWrapper({ className: 'foo' }); + const classnames = wrapper.prop('className'); + expect(classnames).toContain(defaultProps.className); + expect(classnames).toContain('foo'); + }); + + test('contain onClick handler', () => { + const mockFunc = jest.fn(); + const wrapper = getWrapper({ onClick: mockFunc }); + + wrapper.simulate('click'); + expect(mockFunc).toBeCalled(); + expect(wrapper.prop('onClick')).toBeDefined(); + expect(mockFunc.mock.calls.length).toBe(1); + }); + + test('contains img with props', () => { + const wrapper = getWrapper(); + const img = wrapper.find('img'); + + expect(img.prop('alt')).toBe(defaultProps.alt); + expect(img.prop('src')).toBe(defaultProps.icon); + expect(img.prop('className')).toBe('app-ResourceCard__info-cell__icon'); + }); + + test('accept external icon', () => { + const wrapper = getWrapper({ icon: iconMap }); + const img = wrapper.find('img'); + + expect(img.prop('src')).toBe(iconMap); + }); + + test('accept children as label', () => { + const label = This is label; + const wrapper = getWrapper({ children: label }); + + expect(wrapper.contains(label)).toBeTruthy(); + }); +}); diff --git a/jest.config.js b/jest.config.js index 9951545ab..170e19d0d 100755 --- a/jest.config.js +++ b/jest.config.js @@ -48,6 +48,11 @@ module.exports = { '/node_modules/', ], + // ignore watch to include node_modules by mistake. + watchPathIgnorePatterns: [ + '/node_modules/', + ], + // Indicates whether each individual test should be reported during the run verbose: false, }; From f8c2e8325a5084b05d91919ce92bc855e7c9bd54 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Mon, 25 Mar 2019 11:12:45 +0200 Subject: [PATCH 06/55] add heart-filled icon, hide fav button when user not logged in --- app/assets/icons/heart-filled.svg | 10 +++++++ app/shared/resource-card/ResourceCard.js | 19 +++++++++----- app/shared/resource-card/ResourceCard.spec.js | 26 ++++++++++++------- 3 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 app/assets/icons/heart-filled.svg diff --git a/app/assets/icons/heart-filled.svg b/app/assets/icons/heart-filled.svg new file mode 100644 index 000000000..ec29d0177 --- /dev/null +++ b/app/assets/icons/heart-filled.svg @@ -0,0 +1,10 @@ + + + +heart-o + + diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js index f525b9bc2..4988fc91b 100644 --- a/app/shared/resource-card/ResourceCard.js +++ b/app/shared/resource-card/ResourceCard.js @@ -10,7 +10,7 @@ import iconTicket from 'hel-icons/dist/shapes/ticket.svg'; import iconUser from 'hel-icons/dist/shapes/user-o.svg'; import iconHeart from 'hel-icons/dist/shapes/heart-o.svg'; -import iconHeartWhite from 'assets/icons/heart-white.svg'; +import iconHeartFilled from 'assets/icons/heart-filled.svg'; import UnpublishedLabel from 'shared/label/Unpublished'; import { injectT } from 'i18n'; import iconMap from 'assets/icons/map.svg'; @@ -62,7 +62,7 @@ class ResourceCard extends Component { render() { const { - date, resource, t, unit, actions: { favoriteResource, unfavoriteResource } + date, resource, t, unit, actions: { favoriteResource, unfavoriteResource }, isLoggedIn } = this.props; const { pathname, query } = getResourcePageUrlComponents(resource, date); const linkTo = { @@ -157,15 +157,19 @@ class ResourceCard extends Component { - unfavoriteResource(resource.id) : () => favoriteResource(resource.id) } - /> + /> + ) + } ); @@ -181,6 +185,7 @@ ResourceCard.propTypes = { t: PropTypes.func.isRequired, unit: PropTypes.object.isRequired, actions: PropTypes.object, + isLoggedIn: PropTypes.bool, }; export default injectT(ResourceCard); diff --git a/app/shared/resource-card/ResourceCard.spec.js b/app/shared/resource-card/ResourceCard.spec.js index 22669586d..63fb68380 100644 --- a/app/shared/resource-card/ResourceCard.spec.js +++ b/app/shared/resource-card/ResourceCard.spec.js @@ -106,10 +106,10 @@ describe('shared/resource-card/ResourceCard', () => { }); describe('info box', () => { - test('render with 6 ResourceCardInfoCell cells', () => { + test('render with 5 ResourceCardInfoCell cells', () => { const info = getWrapper().find('.app-ResourceCard__info'); const cells = info.find(ResourceCardInfoCell); - expect(cells.length).toEqual(6); + expect(cells.length).toEqual(5); }); test('render with first ResourceCardInfoCell', () => { @@ -121,8 +121,15 @@ describe('shared/resource-card/ResourceCard', () => { expect(cell.prop('onClick')).toBeDefined(); }); - test('render with favorite icon as default', () => { + test('will not render favorite icon as default if user not logged in', () => { const info = getWrapper().find('.app-ResourceCard__info'); + const cell = info.find(ResourceCardInfoCell)[5]; + + expect(cell).toBeUndefined(); + }); + + test('render with favorite icon as default if user logged in', () => { + const info = getWrapper({ isLoggedIn: true }).find('.app-ResourceCard__info'); const cell = info.find(ResourceCardInfoCell).last(); expect(cell.prop('alt')).toEqual(defaultProps.resource.type.name); @@ -130,9 +137,9 @@ describe('shared/resource-card/ResourceCard', () => { expect(cell.prop('onClick')).toBeDefined(); }); - test('render with unfavorite icon when isFavorite is true', () => { + test('render with unfavorite icon when isFavorite is true, user logged in', () => { const info = getWrapper({ - resource: getResource({ isFavorite: true }) + resource: getResource({ isFavorite: true, isLoggedIn: true }) }).find('.app-ResourceCard__info'); const cell = info.find(ResourceCardInfoCell).last(); @@ -141,16 +148,17 @@ describe('shared/resource-card/ResourceCard', () => { expect(cell.prop('onClick')).toBeDefined(); }); - test('invoke favorite func when favorite icon is clicked as default', () => { - const info = getWrapper().find('.app-ResourceCard__info'); + test('invoke favorite func when favorite icon is clicked as default, user logged in', () => { + const info = getWrapper({ isLoggedIn: true }).find('.app-ResourceCard__info'); const cell = info.find(ResourceCardInfoCell).last(); cell.simulate('click'); expect(defaultProps.actions.favoriteResource).toHaveBeenCalledTimes(1); }); - test('invoke set unfavorite func when favorite icon is clicked', () => { + test('invoke set unfavorite func when favorite icon is clicked, user logged in', () => { const info = getWrapper({ - resource: getResource({ isFavorite: true }) + resource: getResource({ isFavorite: true }), + isLoggedIn: true }).find('.app-ResourceCard__info'); const cell = info.find(ResourceCardInfoCell).last(); cell.simulate('click'); From b6a7fa68ed92b9262cc482eb09d6229e8f6b29dc Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Mon, 25 Mar 2019 14:49:13 +0200 Subject: [PATCH 07/55] merging files to clearer view --- app/shared/resource-card/ResourceCard.js | 191 ----------------- .../resource-card/ResourceCardContainer.js | 200 +++++++++++++++++- ....spec.js => ResourceCardContainer.spec.js} | 6 +- 3 files changed, 200 insertions(+), 197 deletions(-) delete mode 100644 app/shared/resource-card/ResourceCard.js rename app/shared/resource-card/{ResourceCard.spec.js => ResourceCardContainer.spec.js} (98%) diff --git a/app/shared/resource-card/ResourceCard.js b/app/shared/resource-card/ResourceCard.js deleted file mode 100644 index 4988fc91b..000000000 --- a/app/shared/resource-card/ResourceCard.js +++ /dev/null @@ -1,191 +0,0 @@ -import classnames from 'classnames'; -import round from 'lodash/round'; -import PropTypes from 'prop-types'; -import queryString from 'query-string'; -import React, { Component, Fragment } from 'react'; -import { Link } from 'react-router-dom'; -import iconHome from 'hel-icons/dist/shapes/home.svg'; -import iconMapMarker from 'hel-icons/dist/shapes/map-marker.svg'; -import iconTicket from 'hel-icons/dist/shapes/ticket.svg'; -import iconUser from 'hel-icons/dist/shapes/user-o.svg'; -import iconHeart from 'hel-icons/dist/shapes/heart-o.svg'; - -import iconHeartFilled from 'assets/icons/heart-filled.svg'; -import UnpublishedLabel from 'shared/label/Unpublished'; -import { injectT } from 'i18n'; -import iconMap from 'assets/icons/map.svg'; -import BackgroundImage from 'shared/background-image'; -import { getMainImage } from 'utils/imageUtils'; -import { getHourlyPrice, getResourcePageUrlComponents } from 'utils/resourceUtils'; -import ResourceAvailability from './label'; -import ResourceCardInfoCell from './info'; - - -class ResourceCard extends Component { - handleSearchByType = () => { - const filters = { search: this.props.resource.type.name }; - this.props.history.push(`/search?${queryString.stringify(filters)}`); - }; - - handleSearchByDistance = () => { - const filters = { distance: this.props.resource.distance }; - this.props.history.push(`/search?${queryString.stringify(filters)}`); - }; - - handleSearchByPeopleCapacity = () => { - const filters = { people: this.props.resource.peopleCapacity }; - this.props.history.push(`/search?${queryString.stringify(filters)}`); - }; - - handleSearchByUnit = () => { - const filters = { unit: this.props.unit.id }; - this.props.history.push(`/search?${queryString.stringify(filters)}`); - }; - - handleLinkClick = () => { - const scrollTop = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop; - const { location, history } = this.props; - const { pathname, search } = location; - history.replace({ pathname, search, state: { scrollTop } }); - }; - - renderDistance(distance) { - const km = distance / 1000; - let formatedDistance = round(km); - if (km < 10) { - formatedDistance = round(km, 1); - } - return `${formatedDistance} km`; - } - - render() { - const { - date, resource, t, unit, actions: { favoriteResource, unfavoriteResource }, isLoggedIn - } = this.props; - const { pathname, query } = getResourcePageUrlComponents(resource, date); - const linkTo = { - pathname, - search: query ? `?${query}` : undefined, - state: { fromSearchResults: true }, - }; - - return ( -
- - - -
-
- - {unit.name} - -
- - {!resource.public && } -
-
- -

{resource.name}

- -
{resource.description}
-
- -
- - - {resource.type ? resource.type.name : '\u00A0'} - - - - - - {t('ResourceCard.peopleCapacity', { people: resource.peopleCapacity })} - - - - - - {getHourlyPrice(t, resource) || '\u00A0'} - - - - - - - {unit.streetAddress} - - - {unit.addressZip} - {' '} - {unit.municipality} - - - - - - - {resource.distance ? this.renderDistance(resource.distance) : '\u00A0'} - - - - {isLoggedIn - && ( - unfavoriteResource(resource.id) - : () => favoriteResource(resource.id) - } - /> - ) - } -
-
- ); - } -} - -ResourceCard.propTypes = { - date: PropTypes.string.isRequired, - location: PropTypes.object.isRequired, - history: PropTypes.object.isRequired, - resource: PropTypes.object.isRequired, - stacked: PropTypes.bool, - t: PropTypes.func.isRequired, - unit: PropTypes.object.isRequired, - actions: PropTypes.object, - isLoggedIn: PropTypes.bool, -}; - -export default injectT(ResourceCard); diff --git a/app/shared/resource-card/ResourceCardContainer.js b/app/shared/resource-card/ResourceCardContainer.js index b2b39e98f..1bcbf180b 100644 --- a/app/shared/resource-card/ResourceCardContainer.js +++ b/app/shared/resource-card/ResourceCardContainer.js @@ -1,9 +1,201 @@ +import classnames from 'classnames'; +import round from 'lodash/round'; +import PropTypes from 'prop-types'; +import queryString from 'query-string'; +import React, { Component, Fragment } from 'react'; +import { Link } from 'react-router-dom'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; +import iconHome from 'hel-icons/dist/shapes/home.svg'; +import iconMapMarker from 'hel-icons/dist/shapes/map-marker.svg'; +import iconTicket from 'hel-icons/dist/shapes/ticket.svg'; +import iconUser from 'hel-icons/dist/shapes/user-o.svg'; +import iconHeart from 'hel-icons/dist/shapes/heart-o.svg'; +import { injectT } from 'i18n'; +import iconHeartFilled from 'assets/icons/heart-filled.svg'; +import UnpublishedLabel from 'shared/label/Unpublished'; +import iconMap from 'assets/icons/map.svg'; +import BackgroundImage from 'shared/background-image'; +import { getMainImage } from 'utils/imageUtils'; +import { getHourlyPrice, getResourcePageUrlComponents } from 'utils/resourceUtils'; +import ResourceAvailability from './label'; +import ResourceCardInfoCell from './info'; import resourceCardSelector from './resourceCardSelector'; -import ResourceCard from './ResourceCard'; -import { favoriteResource, unfavoriteResource } from 'actions/resourceActions'; +import { + favoriteResource, + unfavoriteResource +} from 'actions/resourceActions'; + +class ResourceCard extends Component { + handleSearchByType = () => { + const filters = { search: this.props.resource.type.name }; + this.props.history.push(`/search?${queryString.stringify(filters)}`); + }; + + handleSearchByDistance = () => { + const filters = { distance: this.props.resource.distance }; + this.props.history.push(`/search?${queryString.stringify(filters)}`); + }; + + handleSearchByPeopleCapacity = () => { + const filters = { people: this.props.resource.peopleCapacity }; + this.props.history.push(`/search?${queryString.stringify(filters)}`); + }; + + handleSearchByUnit = () => { + const filters = { unit: this.props.unit.id }; + this.props.history.push(`/search?${queryString.stringify(filters)}`); + }; + + handleLinkClick = () => { + const scrollTop = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop; + const { location, history } = this.props; + const { pathname, search } = location; + history.replace({ pathname, search, state: { scrollTop } }); + }; + + renderDistance(distance) { + const km = distance / 1000; + let formatedDistance = round(km); + if (km < 10) { + formatedDistance = round(km, 1); + } + return `${formatedDistance} km`; + } + + render() { + const { + date, resource, t, unit, actions, isLoggedIn + } = this.props; + const { pathname, query } = getResourcePageUrlComponents(resource, date); + const linkTo = { + pathname, + search: query ? `?${query}` : undefined, + state: { fromSearchResults: true }, + }; + + return ( +
+ + + +
+
+ + {unit.name} + +
+ + {!resource.public && } +
+
+ +

{resource.name}

+ +
{resource.description}
+
+ +
+ + + {resource.type ? resource.type.name : '\u00A0'} + + + + + + {t('ResourceCard.peopleCapacity', { people: resource.peopleCapacity })} + + + + + + {getHourlyPrice(t, resource) || '\u00A0'} + + + + + + + {unit.streetAddress} + + + {unit.addressZip} + {' '} + {unit.municipality} + + + + + + + {resource.distance ? this.renderDistance(resource.distance) : '\u00A0'} + + + + {isLoggedIn + && ( + actions.unfavoriteResource(resource.id) + : () => actions.favoriteResource(resource.id) + } + /> + ) + } +
+
+ ); + } +} + +ResourceCard.propTypes = { + date: PropTypes.string.isRequired, + location: PropTypes.object.isRequired, + history: PropTypes.object.isRequired, + resource: PropTypes.object.isRequired, + stacked: PropTypes.bool, + t: PropTypes.func.isRequired, + unit: PropTypes.object.isRequired, + actions: PropTypes.object, + isLoggedIn: PropTypes.bool, +}; + +const UnconnectedResourceCard = injectT(ResourceCard); + function mapDispatchToProps(dispatch) { const actionCreators = { @@ -14,4 +206,6 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(actionCreators, dispatch) }; } -export default connect(resourceCardSelector, mapDispatchToProps)(ResourceCard); +export { UnconnectedResourceCard }; + +export default connect(resourceCardSelector, mapDispatchToProps)(UnconnectedResourceCard); diff --git a/app/shared/resource-card/ResourceCard.spec.js b/app/shared/resource-card/ResourceCardContainer.spec.js similarity index 98% rename from app/shared/resource-card/ResourceCard.spec.js rename to app/shared/resource-card/ResourceCardContainer.spec.js index 63fb68380..d4f875b72 100644 --- a/app/shared/resource-card/ResourceCard.spec.js +++ b/app/shared/resource-card/ResourceCardContainer.spec.js @@ -11,12 +11,12 @@ import Unit from 'utils/fixtures/Unit'; import { getResourcePageUrlComponents } from 'utils/resourceUtils'; import { shallowWithIntl } from 'utils/testUtils'; import ResourceAvailability from './label/ResourceAvailability'; -import ResourceCard from './ResourceCard'; +import { UnconnectedResourceCard } from './ResourceCardContainer'; import UnpublishedLabel from 'shared/label/Unpublished'; import ResourceCardInfoCell from './info'; import iconHeartWhite from 'assets/icons/heart-white.svg'; -describe('shared/resource-card/ResourceCard', () => { +describe('shared/resource-card/ResourceCardContainer', () => { function getResource(extra) { return Immutable( Resource.build({ @@ -74,7 +74,7 @@ describe('shared/resource-card/ResourceCard', () => { }; function getWrapper(extraProps) { - return shallowWithIntl(); + return shallowWithIntl(); } test('renders an div element', () => { From 48f4541eeb0ce1e8754f3a587fae65f027083a47 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Mon, 25 Mar 2019 15:33:48 +0200 Subject: [PATCH 08/55] Rename component to original name, remove confusing container --- .../{ResourceCardContainer.js => ResourceCard.js} | 0 .../{ResourceCardContainer.spec.js => ResourceCard.spec.js} | 4 ++-- app/shared/resource-card/index.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename app/shared/resource-card/{ResourceCardContainer.js => ResourceCard.js} (100%) rename app/shared/resource-card/{ResourceCardContainer.spec.js => ResourceCard.spec.js} (99%) diff --git a/app/shared/resource-card/ResourceCardContainer.js b/app/shared/resource-card/ResourceCard.js similarity index 100% rename from app/shared/resource-card/ResourceCardContainer.js rename to app/shared/resource-card/ResourceCard.js diff --git a/app/shared/resource-card/ResourceCardContainer.spec.js b/app/shared/resource-card/ResourceCard.spec.js similarity index 99% rename from app/shared/resource-card/ResourceCardContainer.spec.js rename to app/shared/resource-card/ResourceCard.spec.js index d4f875b72..9d6f3d193 100644 --- a/app/shared/resource-card/ResourceCardContainer.spec.js +++ b/app/shared/resource-card/ResourceCard.spec.js @@ -11,12 +11,12 @@ import Unit from 'utils/fixtures/Unit'; import { getResourcePageUrlComponents } from 'utils/resourceUtils'; import { shallowWithIntl } from 'utils/testUtils'; import ResourceAvailability from './label/ResourceAvailability'; -import { UnconnectedResourceCard } from './ResourceCardContainer'; +import { UnconnectedResourceCard } from './ResourceCard'; import UnpublishedLabel from 'shared/label/Unpublished'; import ResourceCardInfoCell from './info'; import iconHeartWhite from 'assets/icons/heart-white.svg'; -describe('shared/resource-card/ResourceCardContainer', () => { +describe('shared/resource-card/ResourceCard', () => { function getResource(extra) { return Immutable( Resource.build({ diff --git a/app/shared/resource-card/index.js b/app/shared/resource-card/index.js index 3738ea4d0..20da4cc63 100644 --- a/app/shared/resource-card/index.js +++ b/app/shared/resource-card/index.js @@ -1,3 +1,3 @@ -import ResourceCardContainer from './ResourceCardContainer'; +import ResourceCard from './ResourceCard'; -export default ResourceCardContainer; +export default ResourceCard; From 911045745a69eeb6bdd5dc38e33d46c8671b9442 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 3 Apr 2019 14:38:58 +0300 Subject: [PATCH 09/55] Show warning message for IE users --- app/index.js | 52 +++++++++++++++++++++++++++++++++++++++++++++------- package.json | 2 ++ yarn.lock | 36 ++++++++++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/app/index.js b/app/index.js index 63b99124e..ae8d9ff46 100644 --- a/app/index.js +++ b/app/index.js @@ -1,5 +1,6 @@ +import 'react-app-polyfill/ie11'; +import { browserName } from 'react-device-detect'; import 'location-origin'; - import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-intl-redux'; @@ -22,10 +23,47 @@ const finalState = Immutable(initialStoreState).merge([initialServerState, initi deep: true, }); const store = configureStore(finalState); +const warningStyle = { + margin: '20px', + padding: '20px', + color: '#5d3d08', + backgroundColor: '#fcf8e3', + border: '2px solid #faebcc', +}; -render( - - {getRoutes()} - , - document.getElementById('root') -); +if (browserName === 'IE') { + render( +
+

+ Currently, Varaamo does not support IE11. + We are investigating this issue and finding a solution. + Meanwhile, use another browser (such as + Chrome + , + Firefox + or + Edge + ). +

+

+ Varaamo ei tue IE11 selainta tällä hetkellä. + Selvitämme ongelmaa sen ratkaisemiseksi. + Sillävälin, käytä toista selainta (kuten + Chrome + , + Firefox + tai + Edge + ). +

+
, + document.getElementById('root') + ); +} else { + render( + + {getRoutes()} + , + document.getElementById('root') + ); +} diff --git a/package.json b/package.json index 535ddf608..82c57851e 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,10 @@ "query-string": "4.2.3", "rc-slider": "8.3.1", "react": "16.8.4", + "react-app-polyfill": "^0.2.2", "react-bootstrap": "0.32.3", "react-day-picker": "7.3.0", + "react-device-detect": "^1.6.2", "react-dom": "16.8.4", "react-helmet": "5.2.0", "react-intl": "2.8.0", diff --git a/yarn.lock b/yarn.lock index 2f98b74bb..02029819c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1249,7 +1249,7 @@ arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asap@~2.0.3: +asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -2039,6 +2039,11 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" +core-js@2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.4.tgz#b8897c062c4d769dd30a0ac5c73976c47f92ea0d" + integrity sha512-05qQ5hXShcqGkPZpXEFLIpxayZscVD2kuMBZewxiIPPEagukO4mqgPA9CWhUvFBJfy3ODdK2p9xyHh7FTU9/7A== + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -5382,7 +5387,7 @@ oauth@0.9.x: version "0.9.15" resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" -object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@4.1.1, object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5932,6 +5937,13 @@ promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" +promise@8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.2.tgz#9dcd0672192c589477d56891271bdc27547ae9f0" + integrity sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw== + dependencies: + asap "~2.0.6" + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -6044,7 +6056,7 @@ querystring@0.2.0, querystring@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -raf@^3.4.0: +raf@3.4.1, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" dependencies: @@ -6156,6 +6168,17 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-app-polyfill@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-0.2.2.tgz#a903b61a8bfd9c5e5f16fc63bebe44d6922a44fb" + integrity sha512-mAYn96B/nB6kWG87Ry70F4D4rsycU43VYTj3ZCbKP+SLJXwC0x6YCbwcICh3uW8/C9s1VgP197yx+w7SCWeDdQ== + dependencies: + core-js "2.6.4" + object-assign "4.1.1" + promise "8.0.2" + raf "3.4.1" + whatwg-fetch "3.0.0" + react-bootstrap@0.32.3: version "0.32.3" resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.32.3.tgz#7ac6f3a8ca099b22d2a8ebb091ab2ed7d39050cf" @@ -6186,6 +6209,11 @@ react-deep-force-update@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-1.1.2.tgz#3d2ae45c2c9040cbb1772be52f8ea1ade6ca2ee1" +react-device-detect@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-1.6.2.tgz#2587e4d1dc15bdfce7a1bf5417624ecd2a2fc31f" + integrity sha512-XIBgwIfpGAknm7tXe/YNbx4ieIR7IyFI3KNfSQk4UjHVy97UHe/nB7iJj8R/dDsI+I/ZzPR4HJ39Gh5tI4nhxw== + react-dom@16.8.4: version "16.8.4" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.4.tgz#1061a8e01a2b3b0c8160037441c3bf00a0e3bc48" @@ -7941,7 +7969,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: dependencies: iconv-lite "0.4.24" -whatwg-fetch@>=0.10.0: +whatwg-fetch@3.0.0, whatwg-fetch@>=0.10.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" From 7a6301ce2afba33a3b73a717c9f55f01fdcf3530 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 3 Apr 2019 16:20:25 +0300 Subject: [PATCH 10/55] Change inline styles to styling in SASS --- app/assets/styles/_layout.scss | 11 +++++++++++ app/index.js | 23 ++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/app/assets/styles/_layout.scss b/app/assets/styles/_layout.scss index d938baa27..46140c83b 100644 --- a/app/assets/styles/_layout.scss +++ b/app/assets/styles/_layout.scss @@ -55,6 +55,17 @@ footer { } } +.warningStyle { + margin: 20px; + padding: 20px; + color: #5d3d08; + background-color: #fcf8e3; + border: 2px solid #faebcc; + a { + text-decoration: none; + } +} + @media (min-width: $screen-lg-min ) { .container { width: 1170px; diff --git a/app/index.js b/app/index.js index ae8d9ff46..6cc40262c 100644 --- a/app/index.js +++ b/app/index.js @@ -23,37 +23,30 @@ const finalState = Immutable(initialStoreState).merge([initialServerState, initi deep: true, }); const store = configureStore(finalState); -const warningStyle = { - margin: '20px', - padding: '20px', - color: '#5d3d08', - backgroundColor: '#fcf8e3', - border: '2px solid #faebcc', -}; if (browserName === 'IE') { render(
-

+

Currently, Varaamo does not support IE11. We are investigating this issue and finding a solution. Meanwhile, use another browser (such as - Chrome + Chrome , - Firefox + Firefox or - Edge + Edge ).

-

+

Varaamo ei tue IE11 selainta tällä hetkellä. Selvitämme ongelmaa sen ratkaisemiseksi. Sillävälin, käytä toista selainta (kuten - Chrome + Chrome , - Firefox + Firefox tai - Edge + Edge ).

, From a7b3deff0d23e6cc0c85dc34c33ee82b46314dde Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 4 Apr 2019 11:36:13 +0300 Subject: [PATCH 11/55] Replace warning styles with open city design system warning alert styles --- app/assets/styles/_layout.scss | 11 ----------- app/index.js | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/app/assets/styles/_layout.scss b/app/assets/styles/_layout.scss index 46140c83b..d938baa27 100644 --- a/app/assets/styles/_layout.scss +++ b/app/assets/styles/_layout.scss @@ -55,17 +55,6 @@ footer { } } -.warningStyle { - margin: 20px; - padding: 20px; - color: #5d3d08; - background-color: #fcf8e3; - border: 2px solid #faebcc; - a { - text-decoration: none; - } -} - @media (min-width: $screen-lg-min ) { .container { width: 1170px; diff --git a/app/index.js b/app/index.js index 6cc40262c..05c4b0aa9 100644 --- a/app/index.js +++ b/app/index.js @@ -27,7 +27,7 @@ const store = configureStore(finalState); if (browserName === 'IE') { render(
-

+

Currently, Varaamo does not support IE11. We are investigating this issue and finding a solution. Meanwhile, use another browser (such as @@ -38,7 +38,7 @@ if (browserName === 'IE') { Edge ).

-

+

Varaamo ei tue IE11 selainta tällä hetkellä. Selvitämme ongelmaa sen ratkaisemiseksi. Sillävälin, käytä toista selainta (kuten From 9837eefedae4b8ac2203ff9fcf91229fd4fc6832 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 4 Apr 2019 12:16:24 +0300 Subject: [PATCH 12/55] Move browser warning message to separate function from index file --- app/index.js | 26 ++--------------- app/pages/browser-warning/BrowserWarning.js | 32 +++++++++++++++++++++ app/pages/browser-warning/index.js | 3 ++ 3 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 app/pages/browser-warning/BrowserWarning.js create mode 100644 app/pages/browser-warning/index.js diff --git a/app/index.js b/app/index.js index 05c4b0aa9..8082ee5b1 100644 --- a/app/index.js +++ b/app/index.js @@ -15,6 +15,7 @@ import { initI18n } from 'i18n'; import configureStore from 'store/configureStore'; import rootReducer from 'state/rootReducer'; import getRoutes from './routes'; +import BrowserWarning from './pages/browser-warning'; const initialStoreState = createStore(rootReducer, {}).getState(); const initialServerState = window.INITIAL_STATE; @@ -26,30 +27,7 @@ const store = configureStore(finalState); if (browserName === 'IE') { render( -

-

- Currently, Varaamo does not support IE11. - We are investigating this issue and finding a solution. - Meanwhile, use another browser (such as - Chrome - , - Firefox - or - Edge - ). -

-

- Varaamo ei tue IE11 selainta tällä hetkellä. - Selvitämme ongelmaa sen ratkaisemiseksi. - Sillävälin, käytä toista selainta (kuten - Chrome - , - Firefox - tai - Edge - ). -

-
, + , document.getElementById('root') ); } else { diff --git a/app/pages/browser-warning/BrowserWarning.js b/app/pages/browser-warning/BrowserWarning.js new file mode 100644 index 000000000..a585a1d00 --- /dev/null +++ b/app/pages/browser-warning/BrowserWarning.js @@ -0,0 +1,32 @@ +import React from 'react'; + +function BrowserWarning() { + return ( +
+

+ Currently, Varaamo does not support IE11. + We are investigating this issue and finding a solution. + Meanwhile, use another browser (such as + Chrome + , + Firefox + or + Edge + ). +

+

+ Varaamo ei tue IE11 selainta tällä hetkellä. + Selvitämme ongelmaa sen ratkaisemiseksi. + Sillävälin, käytä toista selainta (kuten + Chrome + , + Firefox + tai + Edge + ). +

+
+ ); +} + +export default BrowserWarning; diff --git a/app/pages/browser-warning/index.js b/app/pages/browser-warning/index.js new file mode 100644 index 000000000..2cb4f92e4 --- /dev/null +++ b/app/pages/browser-warning/index.js @@ -0,0 +1,3 @@ +import BrowserWarning from './BrowserWarning'; + +export default BrowserWarning; From c67c71799bfdcbf258720ab79aa2e88e621886cb Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 4 Apr 2019 14:12:59 +0300 Subject: [PATCH 13/55] Correct finnish translation in browser warning message --- app/pages/browser-warning/BrowserWarning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pages/browser-warning/BrowserWarning.js b/app/pages/browser-warning/BrowserWarning.js index a585a1d00..4124e949b 100644 --- a/app/pages/browser-warning/BrowserWarning.js +++ b/app/pages/browser-warning/BrowserWarning.js @@ -17,7 +17,7 @@ function BrowserWarning() {

Varaamo ei tue IE11 selainta tällä hetkellä. Selvitämme ongelmaa sen ratkaisemiseksi. - Sillävälin, käytä toista selainta (kuten + Sillä välin, käytä toista selainta (kuten Chrome , Firefox From 3f145a3c7df9c838a4b55468877c3a5fa4396494 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 4 Apr 2019 15:09:28 +0300 Subject: [PATCH 14/55] Unit tests for browser warning message --- .../browser-warning/BrowserWarning.spec.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 app/pages/browser-warning/BrowserWarning.spec.js diff --git a/app/pages/browser-warning/BrowserWarning.spec.js b/app/pages/browser-warning/BrowserWarning.spec.js new file mode 100644 index 000000000..adbbf0903 --- /dev/null +++ b/app/pages/browser-warning/BrowserWarning.spec.js @@ -0,0 +1,25 @@ +import React from 'react'; + +import BrowserWarning from './BrowserWarning'; +import { shallowWithIntl } from 'utils/testUtils'; + +describe('pages/browser-warning/BrowserWarning', () => { + function getWrapper() { + return shallowWithIntl(); + } + + test('renders a browser warning div', () => { + const div = getWrapper().find('div'); + expect(div.length).toBe(1); + }); + + test('renders a browser warning paragraph', () => { + const p = getWrapper().find('p'); + expect(p.length).toBe(2); + }); + + test('renders all specified browser links', () => { + const a = getWrapper().find('a'); + expect(a.length).toBe(6); + }); +}); From 8be17d46f31dd0ecac739d905d7de900d9be3530 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 12 Mar 2019 18:33:07 +0200 Subject: [PATCH 15/55] Initial structure for sort search results --- app/actions/sortActions.js | 36 +++++++++++ app/constants/ActionTypes.js | 4 ++ app/i18n/messages/en.json | 3 + app/i18n/messages/fi.json | 3 + app/i18n/messages/sv.json | 3 + app/pages/search/Sort.js | 78 +++++++++++++++++++++++ app/pages/search/results/SearchResults.js | 9 +++ 7 files changed, 136 insertions(+) create mode 100644 app/actions/sortActions.js create mode 100644 app/pages/search/Sort.js diff --git a/app/actions/sortActions.js b/app/actions/sortActions.js new file mode 100644 index 000000000..366b0bfcd --- /dev/null +++ b/app/actions/sortActions.js @@ -0,0 +1,36 @@ + +import types from 'constants/ActionTypes'; + +import { CALL_API } from 'redux-api-middleware'; + +import schemas from 'store/middleware/Schemas'; +import { + buildAPIUrl, + getErrorTypeDescriptor, + getHeadersCreator, + getRequestTypeDescriptor, + getSuccessTypeDescriptor, +} from 'utils/apiUtils'; + +function sortResources(orderBy) { + return { + [CALL_API]: { + types: [ + getRequestTypeDescriptor(types.API.SORT_RESULTS_GET_REQUEST), + getSuccessTypeDescriptor( + types.API.SORT_RESULTS_GET_SUCCESS, + { schema: schemas.paginatedResourcesSchema } + ), + getErrorTypeDescriptor(types.API.SORT_RESULTS_GET_ERROR), + ], + endpoint: buildAPIUrl(`resource/?order_by=${orderBy}`), + method: 'GET', + headers: getHeadersCreator(), + bailout: state => !state.api.shouldFetch.resources, + }, + }; +} + +export { + sortResources, +}; diff --git a/app/constants/ActionTypes.js b/app/constants/ActionTypes.js index d34ed054e..45f356a9a 100644 --- a/app/constants/ActionTypes.js +++ b/app/constants/ActionTypes.js @@ -44,6 +44,10 @@ export default { SEARCH_RESULTS_GET_REQUEST: 'SEARCH_RESULTS_GET_REQUEST', SEARCH_RESULTS_GET_SUCCESS: 'SEARCH_RESULTS_GET_SUCCESS', + SORT_RESULTS_GET_ERROR: 'SORT_RESULTS_GET_ERROR', + SORT_RESULTS_GET_REQUEST: 'SORT_RESULTS_GET_REQUEST', + SORT_RESULTS_GET_SUCCESS: 'SORT_RESULTS_GET_SUCCESS', + UNITS_GET_ERROR: 'UNITS_GET_ERROR', UNITS_GET_REQUEST: 'UNITS_GET_REQUEST', UNITS_GET_SUCCESS: 'UNITS_GET_SUCCESS', diff --git a/app/i18n/messages/en.json b/app/i18n/messages/en.json index 47bffbe89..819aed96e 100644 --- a/app/i18n/messages/en.json +++ b/app/i18n/messages/en.json @@ -257,6 +257,9 @@ "SearchControlsContainer.unitLabel": "Premise", "SearchPage.title": "Search", "ShowResourcesLink.text": "Show all premises and equipment", + "SideNavbar.close": "Close", + "SideNavbar.toggle": "Guest", + "SortBy.label": "Sort By:", "TestSiteMessage.text": "This is the test version of Varaamo", "TimeRangeControl.timeRangeTitle": "Time range and minimum duration", "TimeRangeControl.title": "{date} at {start}-{end} {hours}h booking", diff --git a/app/i18n/messages/fi.json b/app/i18n/messages/fi.json index e5daed2bc..0ffee8f1f 100644 --- a/app/i18n/messages/fi.json +++ b/app/i18n/messages/fi.json @@ -257,6 +257,9 @@ "SearchControlsContainer.unitLabel": "Toimipiste", "SearchPage.title": "Haku", "ShowResourcesLink.text": "Näytä kaikki tilat ja laitteet", + "SideNavbar.close": "Sulje", + "SideNavbar.toggle": "Vieras", + "SortBy.label": "Järjestä:", "TimeRangeControl.timeRangeTitle": "Käytä aikaväliä ja varauksen minimipituutta", "TimeRangeControl.title": "{date} klo {start}-{end} {hours}h varaus", "TestSiteMessage.text": "Tämä on Varaamon testiversio", diff --git a/app/i18n/messages/sv.json b/app/i18n/messages/sv.json index a719e0f34..fb7fd662a 100644 --- a/app/i18n/messages/sv.json +++ b/app/i18n/messages/sv.json @@ -259,6 +259,9 @@ "SearchControlsContainer.unitLabel": "Utrymmet", "SearchPage.title": "Sök", "ShowResourcesLink.text": "Visa alla utrymmen och apparater", + "SideNavbar.close": "Stäng", + "SideNavbar.toggle": "Gäst", + "SortBy.label": "sortera efter:", "TestSiteMessage.text": "Detta är Varaamo testversion", "TimeRangeControl.timeRangeTitle": "Tidsurval och minsta reserveringstid", "TimeRangeControl.title": "{date} kl. {start}-{end} {hours}h bokning", diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js new file mode 100644 index 000000000..fe4c4abef --- /dev/null +++ b/app/pages/search/Sort.js @@ -0,0 +1,78 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import { injectT } from 'i18n'; +import SelectControl from './controls/SelectControl'; +import { sortResources } from '../../actions/sortActions'; + +class Sort extends Component { + constructor(props) { + super(); + this.state = { + selected: '', + }; + + const { lang } = props; + this.sortOptions = [ + { label: 'Name', value: `resource_name_${lang}` }, + { label: 'Type', value: 'type' }, + { label: 'Premises', value: `unit_name_${lang}` }, + { label: 'People', value: 'people_capacity' }, + { label: 'Open now', value: 'sortByOpenNow' }, + ]; + } + + dispatchSort = (sortName) => { + const { + actions, lang, resources, units + } = this.props; + + this.setState({ selected: sortName }); + actions[sortName]({ lang, resources, units }); + } + + handleChange = (e) => { + console.log(e, 'test handle vhan'); + this.props.actions('resource_name_en'); + } + + render() { + return ( + + ); + } +} + +const mapStateToProps = state => ({ + lang: state.intl.locale, + resources: state.data.resources, + units: state.data.units, +}); + +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(sortResources, dispatch), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(injectT(Sort)); + + +Sort.propTypes = { + actions: PropTypes.func.isRequired, + lang: PropTypes.string.isRequired, + resources: PropTypes.object.isRequired, + units: PropTypes.object.isRequired, + t: PropTypes.func.isRequired, +}; diff --git a/app/pages/search/results/SearchResults.js b/app/pages/search/results/SearchResults.js index 91c42b9f6..9dc9eedac 100644 --- a/app/pages/search/results/SearchResults.js +++ b/app/pages/search/results/SearchResults.js @@ -2,12 +2,15 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Loader from 'react-loader'; import { connect } from 'react-redux'; +import Row from 'react-bootstrap/lib/Row'; +import Col from 'react-bootstrap/lib/Col'; import ResourceCompactList from 'shared/resource-compact-list'; import ResourceList from 'shared/resource-list'; import { scrollTo } from 'utils/domUtils'; import SearchResultsPaging from './SearchResultsPaging'; import searchResultsSelector from './searchResultsSelector'; +import Sort from '../Sort'; export class UnconnectedSearchResults extends Component { constructor(props) { @@ -35,6 +38,12 @@ export class UnconnectedSearchResults extends Component { {!showMap && (

+ + + + + +
Date: Fri, 15 Mar 2019 13:28:25 +0200 Subject: [PATCH 16/55] Sort search results on the basis of API endpoints WIP --- app/pages/search/searchPageSelector.js | 1 + app/state/reducers/ui/searchReducer.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/pages/search/searchPageSelector.js b/app/pages/search/searchPageSelector.js index 331053a24..3e2bbd12e 100644 --- a/app/pages/search/searchPageSelector.js +++ b/app/pages/search/searchPageSelector.js @@ -21,6 +21,7 @@ const orderedSearchResultIdsSelector = createSelector( resourcesSelector, (resourceIds, resources) => { const selectedResources = resourceIds.map(id => resources[id]); + console.log(orderBy(selectedResources, 'distance').map(resource => resource.id)); return orderBy(selectedResources, 'distance').map(resource => resource.id); } ); diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index 4eb4ec17b..4d9386056 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -41,6 +41,19 @@ function searchReducer(state = initialState, action) { }); } + case types.API.SORT_RESULTS_GET_SUCCESS: { + const results = Object.keys(action.payload.entities.resources || {}); + console.log(results, 'results'); + const paginatedResources = Object.values(action.payload.entities.paginatedResources || {}); + const resultCount = paginatedResources.length ? paginatedResources[0].count : 0; + return state.merge({ + resultCount, + results, + searchDone: true, + unitId: null, + }); + } + case types.UI.CHANGE_SEARCH_FILTERS: { const filters = pickSupportedFilters(action.payload); return state.merge({ filters }, { deep: true }); From 6e5de0f914f8ec1c63d44a654f7ef2f4e05b94d4 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Mon, 18 Mar 2019 11:26:43 +0200 Subject: [PATCH 17/55] Sort results functionality for all categories complete --- app/actions/sortActions.js | 36 --------------------- app/pages/search/SearchPage.js | 19 +++++++++++ app/pages/search/Sort.js | 39 ++++++++--------------- app/pages/search/results/SearchResults.js | 9 ------ app/pages/search/searchPageSelector.js | 1 - app/state/reducers/ui/searchReducer.js | 13 -------- app/utils/searchUtils.js | 7 ++-- 7 files changed, 37 insertions(+), 87 deletions(-) delete mode 100644 app/actions/sortActions.js diff --git a/app/actions/sortActions.js b/app/actions/sortActions.js deleted file mode 100644 index 366b0bfcd..000000000 --- a/app/actions/sortActions.js +++ /dev/null @@ -1,36 +0,0 @@ - -import types from 'constants/ActionTypes'; - -import { CALL_API } from 'redux-api-middleware'; - -import schemas from 'store/middleware/Schemas'; -import { - buildAPIUrl, - getErrorTypeDescriptor, - getHeadersCreator, - getRequestTypeDescriptor, - getSuccessTypeDescriptor, -} from 'utils/apiUtils'; - -function sortResources(orderBy) { - return { - [CALL_API]: { - types: [ - getRequestTypeDescriptor(types.API.SORT_RESULTS_GET_REQUEST), - getSuccessTypeDescriptor( - types.API.SORT_RESULTS_GET_SUCCESS, - { schema: schemas.paginatedResourcesSchema } - ), - getErrorTypeDescriptor(types.API.SORT_RESULTS_GET_ERROR), - ], - endpoint: buildAPIUrl(`resource/?order_by=${orderBy}`), - method: 'GET', - headers: getHeadersCreator(), - bailout: state => !state.api.shouldFetch.resources, - }, - }; -} - -export { - sortResources, -}; diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index efc078ebe..ba1c36176 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -2,7 +2,10 @@ import isEqual from 'lodash/isEqual'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; +import queryString from 'query-string'; import { bindActionCreators } from 'redux'; +import Row from 'react-bootstrap/lib/Row'; +import Col from 'react-bootstrap/lib/Col'; import { searchResources, toggleMap } from 'actions/searchActions'; import { changeSearchFilters } from 'actions/uiActions'; @@ -14,6 +17,7 @@ import ResourceMap from 'shared/resource-map'; import SearchControls from './controls'; import searchPageSelector from './searchPageSelector'; import SearchResults from './results/SearchResults'; +import Sort from './Sort'; import MapToggle from './results/MapToggle'; class UnconnectedSearchPage extends Component { @@ -68,6 +72,12 @@ class UnconnectedSearchPage extends Component { this.props.actions.searchResources({ ...filters, ...position }); } + sortBy(newFilters = {}) { + const page = 1; + const filters = { ...this.props.filters, ...newFilters, page }; + this.props.history.push(`/search?${queryString.stringify(filters)}`); + } + render() { const { actions, @@ -96,6 +106,15 @@ class UnconnectedSearchPage extends Component { showMap={showMap} /> )} + +
+ + + this.sortBy(filters)} /> + + +
+
{(searchDone || isFetchingSearchResults) && ( diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index fe4c4abef..01c54401b 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -1,11 +1,9 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; import { injectT } from 'i18n'; import SelectControl from './controls/SelectControl'; -import { sortResources } from '../../actions/sortActions'; class Sort extends Component { constructor(props) { @@ -24,18 +22,16 @@ class Sort extends Component { ]; } - dispatchSort = (sortName) => { - const { - actions, lang, resources, units - } = this.props; - - this.setState({ selected: sortName }); - actions[sortName]({ lang, resources, units }); - } - - handleChange = (e) => { - console.log(e, 'test handle vhan'); - this.props.actions('resource_name_en'); + handleChange = ({ value }) => { + const filters = {}; + if (value === 'sortByOpenNow') { + const now = (new Date()).toISOString(); + filters.orderBy = null; + filters.available_between = `${now},${now}`; + } else { + filters.orderBy = value; + } + this.props.sortBy(filters); } render() { @@ -45,7 +41,6 @@ class Sort extends Component { isLoading={false} label={this.props.t('SortBy.label')} onChange={this.handleChange} - // onConfirm={this.dispatchSort} options={this.sortOptions} value={this.state.selected} /> @@ -54,25 +49,17 @@ class Sort extends Component { } const mapStateToProps = state => ({ - lang: state.intl.locale, - resources: state.data.resources, - units: state.data.units, -}); - -const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(sortResources, dispatch), + lang: state.intl.locale }); export default connect( mapStateToProps, - mapDispatchToProps + {} )(injectT(Sort)); Sort.propTypes = { - actions: PropTypes.func.isRequired, lang: PropTypes.string.isRequired, - resources: PropTypes.object.isRequired, - units: PropTypes.object.isRequired, t: PropTypes.func.isRequired, + sortBy: PropTypes.func.isRequired }; diff --git a/app/pages/search/results/SearchResults.js b/app/pages/search/results/SearchResults.js index 9dc9eedac..91c42b9f6 100644 --- a/app/pages/search/results/SearchResults.js +++ b/app/pages/search/results/SearchResults.js @@ -2,15 +2,12 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Loader from 'react-loader'; import { connect } from 'react-redux'; -import Row from 'react-bootstrap/lib/Row'; -import Col from 'react-bootstrap/lib/Col'; import ResourceCompactList from 'shared/resource-compact-list'; import ResourceList from 'shared/resource-list'; import { scrollTo } from 'utils/domUtils'; import SearchResultsPaging from './SearchResultsPaging'; import searchResultsSelector from './searchResultsSelector'; -import Sort from '../Sort'; export class UnconnectedSearchResults extends Component { constructor(props) { @@ -38,12 +35,6 @@ export class UnconnectedSearchResults extends Component { {!showMap && (
- - - - - -
{ const selectedResources = resourceIds.map(id => resources[id]); - console.log(orderBy(selectedResources, 'distance').map(resource => resource.id)); return orderBy(selectedResources, 'distance').map(resource => resource.id); } ); diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index 4d9386056..4eb4ec17b 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -41,19 +41,6 @@ function searchReducer(state = initialState, action) { }); } - case types.API.SORT_RESULTS_GET_SUCCESS: { - const results = Object.keys(action.payload.entities.resources || {}); - console.log(results, 'results'); - const paginatedResources = Object.values(action.payload.entities.paginatedResources || {}); - const resultCount = paginatedResources.length ? paginatedResources[0].count : 0; - return state.merge({ - resultCount, - results, - searchDone: true, - unitId: null, - }); - } - case types.UI.CHANGE_SEARCH_FILTERS: { const filters = pickSupportedFilters(action.payload); return state.merge({ filters }, { deep: true }); diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index 6360716b3..0df0aa0c6 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -18,9 +18,12 @@ function getFetchParamsFromFilters(filters) { filters.duration ), { purpose: filters.purpose === 'all' ? '' : filters.purpose }, - { page: filters.page || 1 } + { page: filters.page || 1 }, + { order_by: filters.orderBy || '' } ); - + if (filters.available_between) { + all.available_between = filters.available_between; + } return omit(all, 'date', 'duration', 'useTimeRange'); } From b9ca8684f768c05e646752171fec0539053d4b34 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Mon, 18 Mar 2019 12:26:02 +0200 Subject: [PATCH 18/55] Remove stuffs from action types missed to remove before --- app/constants/ActionTypes.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/constants/ActionTypes.js b/app/constants/ActionTypes.js index 45f356a9a..d34ed054e 100644 --- a/app/constants/ActionTypes.js +++ b/app/constants/ActionTypes.js @@ -44,10 +44,6 @@ export default { SEARCH_RESULTS_GET_REQUEST: 'SEARCH_RESULTS_GET_REQUEST', SEARCH_RESULTS_GET_SUCCESS: 'SEARCH_RESULTS_GET_SUCCESS', - SORT_RESULTS_GET_ERROR: 'SORT_RESULTS_GET_ERROR', - SORT_RESULTS_GET_REQUEST: 'SORT_RESULTS_GET_REQUEST', - SORT_RESULTS_GET_SUCCESS: 'SORT_RESULTS_GET_SUCCESS', - UNITS_GET_ERROR: 'UNITS_GET_ERROR', UNITS_GET_REQUEST: 'UNITS_GET_REQUEST', UNITS_GET_SUCCESS: 'UNITS_GET_SUCCESS', From a2c610ea37b48a31229a42b7cce3cb53d7e520e7 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 19 Mar 2019 17:55:39 +0200 Subject: [PATCH 19/55] Remove Grid from page wrapper and add Wrap sort result and sort control by Grid --- app/pages/search/SearchPage.js | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index ba1c36176..9993c16bc 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -6,6 +6,7 @@ import queryString from 'query-string'; import { bindActionCreators } from 'redux'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; +import Grid from 'react-bootstrap/lib/Grid'; import { searchResources, toggleMap } from 'actions/searchActions'; import { changeSearchFilters } from 'actions/uiActions'; @@ -107,30 +108,30 @@ class UnconnectedSearchPage extends Component { /> )} -
+ this.sortBy(filters)} /> -
- -
- {(searchDone || isFetchingSearchResults) && ( - - )} -
-
+ +
+ {(searchDone || isFetchingSearchResults) && ( + + )} +
+
+
); } From 8df00853b25c9f34e915271ed67f617e039e6d78 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 19 Mar 2019 20:09:56 +0200 Subject: [PATCH 20/55] Fix typo in translation file --- app/i18n/messages/sv.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/i18n/messages/sv.json b/app/i18n/messages/sv.json index fb7fd662a..e69bdc866 100644 --- a/app/i18n/messages/sv.json +++ b/app/i18n/messages/sv.json @@ -261,7 +261,7 @@ "ShowResourcesLink.text": "Visa alla utrymmen och apparater", "SideNavbar.close": "Stäng", "SideNavbar.toggle": "Gäst", - "SortBy.label": "sortera efter:", + "SortBy.label": "Sortera efter:", "TestSiteMessage.text": "Detta är Varaamo testversion", "TimeRangeControl.timeRangeTitle": "Tidsurval och minsta reserveringstid", "TimeRangeControl.title": "{date} kl. {start}-{end} {hours}h bokning", From e4fb7e75645bb05d6acdaee11fcc03410c022aee Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 19 Mar 2019 20:30:06 +0200 Subject: [PATCH 21/55] Remove not needed test from PageWrapper --- app/pages/PageWrapper.spec.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/pages/PageWrapper.spec.js b/app/pages/PageWrapper.spec.js index 7b54f5900..db38ce699 100644 --- a/app/pages/PageWrapper.spec.js +++ b/app/pages/PageWrapper.spec.js @@ -38,9 +38,4 @@ describe('pages/PageWrapper', () => { const gridWrapper = getWrapper().find(Grid); expect(gridWrapper).toHaveLength(1); }); - - test('renders a fluid Grid if fluid prop', () => { - const gridWrapper = getWrapper({ fluid: true }).find(Grid); - expect(gridWrapper).toHaveLength(1); - }); }); From 3b42fa1a665c57476ad879ba3a61ae73ee6ceb91 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 19 Mar 2019 20:49:54 +0200 Subject: [PATCH 22/55] Add test in SearchPage and remove unneeded test from PageWrapper --- app/pages/PageWrapper.spec.js | 5 +++++ app/pages/search/SearchPage.spec.js | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/app/pages/PageWrapper.spec.js b/app/pages/PageWrapper.spec.js index db38ce699..7b54f5900 100644 --- a/app/pages/PageWrapper.spec.js +++ b/app/pages/PageWrapper.spec.js @@ -38,4 +38,9 @@ describe('pages/PageWrapper', () => { const gridWrapper = getWrapper().find(Grid); expect(gridWrapper).toHaveLength(1); }); + + test('renders a fluid Grid if fluid prop', () => { + const gridWrapper = getWrapper({ fluid: true }).find(Grid); + expect(gridWrapper).toHaveLength(1); + }); }); diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index b4418dc02..01dfc5f60 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -1,6 +1,7 @@ import React from 'react'; import Immutable from 'seamless-immutable'; import simple from 'simple-mock'; +import Grid from 'react-bootstrap/lib/Grid'; import PageWrapper from 'pages/PageWrapper'; import { shallowWithIntl } from 'utils/testUtils'; @@ -85,6 +86,11 @@ describe('pages/search/SearchPage', () => { expect(resourceMap.prop('selectedUnitId')).toBe(props.selectedUnitId); }); + test('renders a normal Grid', () => { + const gridWrapper = getWrapper().find(Grid); + expect(gridWrapper).toHaveLength(1); + }); + describe('SearchResults', () => { function getSearchResults(props) { return getWrapper(props).find(SearchResults); From 9ad47b754cda1923c13180df7fcf3ffd4f6cf222 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 20 Mar 2019 09:58:12 +0200 Subject: [PATCH 23/55] Make label value as constants --- app/constants/AppConstants.js | 7 +++++++ app/pages/search/Sort.js | 14 +++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/constants/AppConstants.js b/app/constants/AppConstants.js index caed2752f..a85525f1e 100644 --- a/app/constants/AppConstants.js +++ b/app/constants/AppConstants.js @@ -68,4 +68,11 @@ export default { TIME_FORMAT: 'H:mm', TIME_SLOT_DEFAULT_LENGTH: 30, TRACKING: SETTINGS.TRACKING, + SORT_BY_OPTIONS: { + RESOURCE_NAME: 'resource_name_lang', + TYPE: 'type_name_lang', + PREMISES: 'unit_name_lang', + PEOPLE: 'people_capacity', + OPEN_NOW: 'sortByOpenNow' + } }; diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 01c54401b..48b95fcd9 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -3,6 +3,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { injectT } from 'i18n'; +import CONSTANTS from '../../constants/AppConstants'; import SelectControl from './controls/SelectControl'; class Sort extends Component { @@ -11,20 +12,19 @@ class Sort extends Component { this.state = { selected: '', }; - const { lang } = props; this.sortOptions = [ - { label: 'Name', value: `resource_name_${lang}` }, - { label: 'Type', value: 'type' }, - { label: 'Premises', value: `unit_name_${lang}` }, - { label: 'People', value: 'people_capacity' }, - { label: 'Open now', value: 'sortByOpenNow' }, + { label: 'Name', value: CONSTANTS.SORT_BY_OPTIONS.RESOURCE_NAME.replace('lang', lang) }, + { label: 'Type', value: CONSTANTS.SORT_BY_OPTIONS.TYPE.replace('lang', lang) }, + { label: 'Premises', value: CONSTANTS.SORT_BY_OPTIONS.PREMISES.replace('lang', lang) }, + { label: 'People', value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }, + { label: 'Open now', value: CONSTANTS.SORT_BY_OPTIONS.OPEN_NOW }, ]; } handleChange = ({ value }) => { const filters = {}; - if (value === 'sortByOpenNow') { + if (value === CONSTANTS.SORT_BY_OPTIONS.OPEN_NOW) { const now = (new Date()).toISOString(); filters.orderBy = null; filters.available_between = `${now},${now}`; From 182f955230bb5ec78cb5710648c4aa17d318ebfb Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 20 Mar 2019 10:10:09 +0200 Subject: [PATCH 24/55] Do not include order by filter at all if no orderBy value is present --- app/utils/searchUtils.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index 0df0aa0c6..688ebb588 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -19,11 +19,9 @@ function getFetchParamsFromFilters(filters) { ), { purpose: filters.purpose === 'all' ? '' : filters.purpose }, { page: filters.page || 1 }, - { order_by: filters.orderBy || '' } + { ...(filters.orderBy ? { order_by: filters.orderBy } : {}) }, + { ...(filters.available_between ? { available_between: filters.available_between } : {}) } ); - if (filters.available_between) { - all.available_between = filters.available_between; - } return omit(all, 'date', 'duration', 'useTimeRange'); } From 76b79be4742b5e4b5f200d5edbd1f61edb7c99b1 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 20 Mar 2019 13:35:37 +0200 Subject: [PATCH 25/55] Wrap sort and search result by PageWrapper and revert previous test case changes --- app/pages/search/SearchPage.js | 36 +++++++++++++---------------- app/pages/search/SearchPage.spec.js | 5 ---- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index 9993c16bc..b2e7db8c7 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -6,7 +6,6 @@ import queryString from 'query-string'; import { bindActionCreators } from 'redux'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; -import Grid from 'react-bootstrap/lib/Grid'; import { searchResources, toggleMap } from 'actions/searchActions'; import { changeSearchFilters } from 'actions/uiActions'; @@ -108,30 +107,27 @@ class UnconnectedSearchPage extends Component { /> )} - + this.sortBy(filters)} /> - - -
- {(searchDone || isFetchingSearchResults) && ( - - )} -
-
-
+
+ {(searchDone || isFetchingSearchResults) && ( + + )} +
+
); } diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index 01dfc5f60..b7f592b5f 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -86,11 +86,6 @@ describe('pages/search/SearchPage', () => { expect(resourceMap.prop('selectedUnitId')).toBe(props.selectedUnitId); }); - test('renders a normal Grid', () => { - const gridWrapper = getWrapper().find(Grid); - expect(gridWrapper).toHaveLength(1); - }); - describe('SearchResults', () => { function getSearchResults(props) { return getWrapper(props).find(SearchResults); From e19002233378240f65576868f81b1972b7eb57ba Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 20 Mar 2019 13:48:06 +0200 Subject: [PATCH 26/55] Remove unused import Grid from failing SearchPage test --- app/pages/search/SearchPage.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index b7f592b5f..b4418dc02 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -1,7 +1,6 @@ import React from 'react'; import Immutable from 'seamless-immutable'; import simple from 'simple-mock'; -import Grid from 'react-bootstrap/lib/Grid'; import PageWrapper from 'pages/PageWrapper'; import { shallowWithIntl } from 'utils/testUtils'; From 0bf6c07aaa87c51122f0e89eabd4de02633da423 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 20 Mar 2019 16:50:15 +0200 Subject: [PATCH 27/55] Add endTime for open now sort --- app/pages/search/Sort.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 48b95fcd9..4896cd27a 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; +import moment from 'moment'; import { injectT } from 'i18n'; import CONSTANTS from '../../constants/AppConstants'; @@ -26,8 +27,9 @@ class Sort extends Component { const filters = {}; if (value === CONSTANTS.SORT_BY_OPTIONS.OPEN_NOW) { const now = (new Date()).toISOString(); + const endOfDay = (moment().endOf('day')).toISOString(); filters.orderBy = null; - filters.available_between = `${now},${now}`; + filters.available_between = `${now},${endOfDay}`; } else { filters.orderBy = value; } From 089eba630d6bde94896b48e199e87875a00e9677 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 21 Mar 2019 10:07:35 +0200 Subject: [PATCH 28/55] Add unit test for Sort component in SearchPage --- app/pages/search/SearchPage.spec.js | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index b4418dc02..031465b42 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -1,11 +1,13 @@ import React from 'react'; import Immutable from 'seamless-immutable'; +import Row from 'react-bootstrap/lib/Row'; import simple from 'simple-mock'; import PageWrapper from 'pages/PageWrapper'; import { shallowWithIntl } from 'utils/testUtils'; import ResourceMap from 'shared/resource-map'; import { UnconnectedSearchPage as SearchPage } from './SearchPage'; +import Sort from './Sort'; import SearchControls from './controls'; import SearchResults from './results/SearchResults'; import MapToggle from './results/MapToggle'; @@ -85,6 +87,16 @@ describe('pages/search/SearchPage', () => { expect(resourceMap.prop('selectedUnitId')).toBe(props.selectedUnitId); }); + test('renders an Row element', () => { + expect(getWrapper().find(Row)).toHaveLength(1); + }); + + test('renders a Sort component with correct props', () => { + const sort = getWrapper().find(Sort); + expect(sort).toHaveLength(1); + expect(typeof sort.prop('sortBy')).toBe('function'); + }); + describe('SearchResults', () => { function getSearchResults(props) { return getWrapper(props).find(SearchResults); @@ -214,6 +226,24 @@ describe('pages/search/SearchPage', () => { }); }); + describe('sortBy', () => { + const pushMock = simple.mock(); + beforeAll(() => { + const instance = getWrapper( + { + history: { push: pushMock } + } + ).instance(); + instance.sortBy({ orderBy: 'name' }); + }); + test('changes history with correct queryString', () => { + expect(pushMock.callCount).toBe(1); + expect(pushMock.lastCall.args[0]).toEqual( + '/search?date=2015-10-10&orderBy=name&page=1&purpose=some-purpose' + ); + }); + }); + describe('if search filters did change and url has query part', () => { let nextProps; From a862e8929ba7af95b144a442994887e9ae1f1dd4 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Thu, 21 Mar 2019 20:25:52 +0200 Subject: [PATCH 29/55] Drop open now for now as it is not yet supported by API --- app/constants/AppConstants.js | 1 - app/pages/search/Sort.js | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/constants/AppConstants.js b/app/constants/AppConstants.js index a85525f1e..c3d887956 100644 --- a/app/constants/AppConstants.js +++ b/app/constants/AppConstants.js @@ -73,6 +73,5 @@ export default { TYPE: 'type_name_lang', PREMISES: 'unit_name_lang', PEOPLE: 'people_capacity', - OPEN_NOW: 'sortByOpenNow' } }; diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 4896cd27a..d9627f2d1 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -1,7 +1,6 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { connect } from 'react-redux'; -import moment from 'moment'; import { injectT } from 'i18n'; import CONSTANTS from '../../constants/AppConstants'; @@ -19,20 +18,12 @@ class Sort extends Component { { label: 'Type', value: CONSTANTS.SORT_BY_OPTIONS.TYPE.replace('lang', lang) }, { label: 'Premises', value: CONSTANTS.SORT_BY_OPTIONS.PREMISES.replace('lang', lang) }, { label: 'People', value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }, - { label: 'Open now', value: CONSTANTS.SORT_BY_OPTIONS.OPEN_NOW }, ]; } handleChange = ({ value }) => { const filters = {}; - if (value === CONSTANTS.SORT_BY_OPTIONS.OPEN_NOW) { - const now = (new Date()).toISOString(); - const endOfDay = (moment().endOf('day')).toISOString(); - filters.orderBy = null; - filters.available_between = `${now},${endOfDay}`; - } else { - filters.orderBy = value; - } + filters.orderBy = value; this.props.sortBy(filters); } From 5720a6547f399ea1b9269e4be9b7579bdf47de0a Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 12 Mar 2019 18:33:07 +0200 Subject: [PATCH 30/55] Initial structure for sort search results --- app/actions/sortActions.js | 36 +++++++++++++++++++++++ app/constants/ActionTypes.js | 4 +++ app/pages/search/results/SearchResults.js | 9 ++++++ 3 files changed, 49 insertions(+) create mode 100644 app/actions/sortActions.js diff --git a/app/actions/sortActions.js b/app/actions/sortActions.js new file mode 100644 index 000000000..366b0bfcd --- /dev/null +++ b/app/actions/sortActions.js @@ -0,0 +1,36 @@ + +import types from 'constants/ActionTypes'; + +import { CALL_API } from 'redux-api-middleware'; + +import schemas from 'store/middleware/Schemas'; +import { + buildAPIUrl, + getErrorTypeDescriptor, + getHeadersCreator, + getRequestTypeDescriptor, + getSuccessTypeDescriptor, +} from 'utils/apiUtils'; + +function sortResources(orderBy) { + return { + [CALL_API]: { + types: [ + getRequestTypeDescriptor(types.API.SORT_RESULTS_GET_REQUEST), + getSuccessTypeDescriptor( + types.API.SORT_RESULTS_GET_SUCCESS, + { schema: schemas.paginatedResourcesSchema } + ), + getErrorTypeDescriptor(types.API.SORT_RESULTS_GET_ERROR), + ], + endpoint: buildAPIUrl(`resource/?order_by=${orderBy}`), + method: 'GET', + headers: getHeadersCreator(), + bailout: state => !state.api.shouldFetch.resources, + }, + }; +} + +export { + sortResources, +}; diff --git a/app/constants/ActionTypes.js b/app/constants/ActionTypes.js index d34ed054e..45f356a9a 100644 --- a/app/constants/ActionTypes.js +++ b/app/constants/ActionTypes.js @@ -44,6 +44,10 @@ export default { SEARCH_RESULTS_GET_REQUEST: 'SEARCH_RESULTS_GET_REQUEST', SEARCH_RESULTS_GET_SUCCESS: 'SEARCH_RESULTS_GET_SUCCESS', + SORT_RESULTS_GET_ERROR: 'SORT_RESULTS_GET_ERROR', + SORT_RESULTS_GET_REQUEST: 'SORT_RESULTS_GET_REQUEST', + SORT_RESULTS_GET_SUCCESS: 'SORT_RESULTS_GET_SUCCESS', + UNITS_GET_ERROR: 'UNITS_GET_ERROR', UNITS_GET_REQUEST: 'UNITS_GET_REQUEST', UNITS_GET_SUCCESS: 'UNITS_GET_SUCCESS', diff --git a/app/pages/search/results/SearchResults.js b/app/pages/search/results/SearchResults.js index 91c42b9f6..9dc9eedac 100644 --- a/app/pages/search/results/SearchResults.js +++ b/app/pages/search/results/SearchResults.js @@ -2,12 +2,15 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Loader from 'react-loader'; import { connect } from 'react-redux'; +import Row from 'react-bootstrap/lib/Row'; +import Col from 'react-bootstrap/lib/Col'; import ResourceCompactList from 'shared/resource-compact-list'; import ResourceList from 'shared/resource-list'; import { scrollTo } from 'utils/domUtils'; import SearchResultsPaging from './SearchResultsPaging'; import searchResultsSelector from './searchResultsSelector'; +import Sort from '../Sort'; export class UnconnectedSearchResults extends Component { constructor(props) { @@ -35,6 +38,12 @@ export class UnconnectedSearchResults extends Component { {!showMap && (
+ + + + + +
Date: Fri, 15 Mar 2019 13:28:25 +0200 Subject: [PATCH 31/55] Sort search results on the basis of API endpoints WIP --- app/pages/search/searchPageSelector.js | 1 + app/state/reducers/ui/searchReducer.js | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/pages/search/searchPageSelector.js b/app/pages/search/searchPageSelector.js index 331053a24..3e2bbd12e 100644 --- a/app/pages/search/searchPageSelector.js +++ b/app/pages/search/searchPageSelector.js @@ -21,6 +21,7 @@ const orderedSearchResultIdsSelector = createSelector( resourcesSelector, (resourceIds, resources) => { const selectedResources = resourceIds.map(id => resources[id]); + console.log(orderBy(selectedResources, 'distance').map(resource => resource.id)); return orderBy(selectedResources, 'distance').map(resource => resource.id); } ); diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index 4eb4ec17b..4d9386056 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -41,6 +41,19 @@ function searchReducer(state = initialState, action) { }); } + case types.API.SORT_RESULTS_GET_SUCCESS: { + const results = Object.keys(action.payload.entities.resources || {}); + console.log(results, 'results'); + const paginatedResources = Object.values(action.payload.entities.paginatedResources || {}); + const resultCount = paginatedResources.length ? paginatedResources[0].count : 0; + return state.merge({ + resultCount, + results, + searchDone: true, + unitId: null, + }); + } + case types.UI.CHANGE_SEARCH_FILTERS: { const filters = pickSupportedFilters(action.payload); return state.merge({ filters }, { deep: true }); From 318b2469a3d7e8acabf4a6dda0f5b3d26c17f1ff Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Sun, 24 Mar 2019 16:18:14 +0200 Subject: [PATCH 32/55] Unit test for Sort component --- app/pages/search/Sort.js | 2 +- app/pages/search/Sort.spec.js | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 app/pages/search/Sort.spec.js diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index d9627f2d1..cd22a7f4c 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -6,7 +6,7 @@ import { injectT } from 'i18n'; import CONSTANTS from '../../constants/AppConstants'; import SelectControl from './controls/SelectControl'; -class Sort extends Component { +export class Sort extends Component { constructor(props) { super(); this.state = { diff --git a/app/pages/search/Sort.spec.js b/app/pages/search/Sort.spec.js new file mode 100644 index 000000000..e13084909 --- /dev/null +++ b/app/pages/search/Sort.spec.js @@ -0,0 +1,40 @@ +import React from 'react'; +import simple from 'simple-mock'; +import { shallow } from 'enzyme'; + +import SelectControl from './controls/SelectControl'; +import { Sort } from './Sort'; +import CONSTANTS from '../../constants/AppConstants'; + +describe('pages/search/Sort', () => { + const defaultProps = { + t: () => 'label', + lang: 'en', + sortBy: () => 'people' + }; + function getWrapper(props) { + return shallow(); + } + + describe('render', () => { + test('renders SelectControl for sort with correct props', () => { + const wrapper = getWrapper({}); + const selectControl = wrapper.find(SelectControl); + expect(selectControl).toHaveLength(1); + expect(selectControl.prop('id')).toBe('sort'); + expect(selectControl.prop('label')).toBeDefined(); + expect(selectControl.prop('onChange')).toBeDefined(); + expect(selectControl.prop('value')).toBeDefined(); + }); + }); + + describe('handleChange', () => { + test('calls this.props.onChange with correct value', () => { + const sortBy = simple.mock(); + const instance = getWrapper({ sortBy }).instance(); + instance.handleChange({ value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }); + expect(sortBy.callCount).toBe(1); + expect(sortBy.lastCall.args[0]).toEqual({ orderBy: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }); + }); + }); +}); From 259e2179a50831dad5a02257041c29e32ab61fd8 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Sun, 24 Mar 2019 16:26:10 +0200 Subject: [PATCH 33/55] Remove available_between line missed to remove in previous commit --- app/utils/searchUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index 688ebb588..a08ccd6d1 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -20,7 +20,6 @@ function getFetchParamsFromFilters(filters) { { purpose: filters.purpose === 'all' ? '' : filters.purpose }, { page: filters.page || 1 }, { ...(filters.orderBy ? { order_by: filters.orderBy } : {}) }, - { ...(filters.available_between ? { available_between: filters.available_between } : {}) } ); return omit(all, 'date', 'duration', 'useTimeRange'); } From 89e250f8ad0da3a3d42db9b851d17dcca0f12f5c Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Mon, 25 Mar 2019 10:02:50 +0200 Subject: [PATCH 34/55] Fix error : Using exported name 'Sort' as identifier for default export --- app/pages/search/Sort.js | 6 +++--- app/pages/search/Sort.spec.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index cd22a7f4c..3af8f4cde 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -6,7 +6,7 @@ import { injectT } from 'i18n'; import CONSTANTS from '../../constants/AppConstants'; import SelectControl from './controls/SelectControl'; -export class Sort extends Component { +export class UnconnectedSort extends Component { constructor(props) { super(); this.state = { @@ -48,10 +48,10 @@ const mapStateToProps = state => ({ export default connect( mapStateToProps, {} -)(injectT(Sort)); +)(injectT(UnconnectedSort)); -Sort.propTypes = { +UnconnectedSort.propTypes = { lang: PropTypes.string.isRequired, t: PropTypes.func.isRequired, sortBy: PropTypes.func.isRequired diff --git a/app/pages/search/Sort.spec.js b/app/pages/search/Sort.spec.js index e13084909..ecabe81d2 100644 --- a/app/pages/search/Sort.spec.js +++ b/app/pages/search/Sort.spec.js @@ -3,7 +3,7 @@ import simple from 'simple-mock'; import { shallow } from 'enzyme'; import SelectControl from './controls/SelectControl'; -import { Sort } from './Sort'; +import { UnconnectedSort as Sort } from './Sort'; import CONSTANTS from '../../constants/AppConstants'; describe('pages/search/Sort', () => { From 173cffc054c32cd7aab9ad305a75505d47539d50 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 26 Mar 2019 11:23:52 +0200 Subject: [PATCH 35/55] Add todo info for later development --- app/constants/AppConstants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/constants/AppConstants.js b/app/constants/AppConstants.js index c3d887956..6bf39377a 100644 --- a/app/constants/AppConstants.js +++ b/app/constants/AppConstants.js @@ -73,5 +73,6 @@ export default { TYPE: 'type_name_lang', PREMISES: 'unit_name_lang', PEOPLE: 'people_capacity', + // TODO: sortby 'open now' should be implemented later after API support it } }; From 81dd4f34076f5d121e5d1a3077cb9184e68efa05 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 26 Mar 2019 11:46:26 +0200 Subject: [PATCH 36/55] Remove duplicate display of sort dropdown, correct display is from SearchPage. --- app/pages/search/results/SearchResults.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/pages/search/results/SearchResults.js b/app/pages/search/results/SearchResults.js index 9dc9eedac..91c42b9f6 100644 --- a/app/pages/search/results/SearchResults.js +++ b/app/pages/search/results/SearchResults.js @@ -2,15 +2,12 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import Loader from 'react-loader'; import { connect } from 'react-redux'; -import Row from 'react-bootstrap/lib/Row'; -import Col from 'react-bootstrap/lib/Col'; import ResourceCompactList from 'shared/resource-compact-list'; import ResourceList from 'shared/resource-list'; import { scrollTo } from 'utils/domUtils'; import SearchResultsPaging from './SearchResultsPaging'; import searchResultsSelector from './searchResultsSelector'; -import Sort from '../Sort'; export class UnconnectedSearchResults extends Component { constructor(props) { @@ -38,12 +35,6 @@ export class UnconnectedSearchResults extends Component { {!showMap && (
- - - - - -
Date: Tue, 26 Mar 2019 12:04:19 +0200 Subject: [PATCH 37/55] Minor code clean up --- app/constants/ActionTypes.js | 4 ---- app/pages/search/SearchPage.js | 2 +- app/pages/search/searchPageSelector.js | 1 - app/state/reducers/ui/searchReducer.js | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/constants/ActionTypes.js b/app/constants/ActionTypes.js index 45f356a9a..d34ed054e 100644 --- a/app/constants/ActionTypes.js +++ b/app/constants/ActionTypes.js @@ -44,10 +44,6 @@ export default { SEARCH_RESULTS_GET_REQUEST: 'SEARCH_RESULTS_GET_REQUEST', SEARCH_RESULTS_GET_SUCCESS: 'SEARCH_RESULTS_GET_SUCCESS', - SORT_RESULTS_GET_ERROR: 'SORT_RESULTS_GET_ERROR', - SORT_RESULTS_GET_REQUEST: 'SORT_RESULTS_GET_REQUEST', - SORT_RESULTS_GET_SUCCESS: 'SORT_RESULTS_GET_SUCCESS', - UNITS_GET_ERROR: 'UNITS_GET_ERROR', UNITS_GET_REQUEST: 'UNITS_GET_REQUEST', UNITS_GET_SUCCESS: 'UNITS_GET_SUCCESS', diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index b2e7db8c7..b8cc8f923 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -109,7 +109,7 @@ class UnconnectedSearchPage extends Component { - + this.sortBy(filters)} /> diff --git a/app/pages/search/searchPageSelector.js b/app/pages/search/searchPageSelector.js index 3e2bbd12e..331053a24 100644 --- a/app/pages/search/searchPageSelector.js +++ b/app/pages/search/searchPageSelector.js @@ -21,7 +21,6 @@ const orderedSearchResultIdsSelector = createSelector( resourcesSelector, (resourceIds, resources) => { const selectedResources = resourceIds.map(id => resources[id]); - console.log(orderBy(selectedResources, 'distance').map(resource => resource.id)); return orderBy(selectedResources, 'distance').map(resource => resource.id); } ); diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index 4d9386056..e9d60e9e2 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -43,7 +43,6 @@ function searchReducer(state = initialState, action) { case types.API.SORT_RESULTS_GET_SUCCESS: { const results = Object.keys(action.payload.entities.resources || {}); - console.log(results, 'results'); const paginatedResources = Object.values(action.payload.entities.paginatedResources || {}); const resultCount = paginatedResources.length ? paginatedResources[0].count : 0; return state.merge({ From 36006ff5be63ed55dc52217da614ea0a2b5d97e9 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 26 Mar 2019 12:08:38 +0200 Subject: [PATCH 38/55] Change CALL_API to RSAA --- app/actions/sortActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/actions/sortActions.js b/app/actions/sortActions.js index 366b0bfcd..cbdb5c495 100644 --- a/app/actions/sortActions.js +++ b/app/actions/sortActions.js @@ -1,7 +1,7 @@ import types from 'constants/ActionTypes'; -import { CALL_API } from 'redux-api-middleware'; +import { RSAA } from 'redux-api-middleware'; import schemas from 'store/middleware/Schemas'; import { @@ -14,7 +14,7 @@ import { function sortResources(orderBy) { return { - [CALL_API]: { + [RSAA]: { types: [ getRequestTypeDescriptor(types.API.SORT_RESULTS_GET_REQUEST), getSuccessTypeDescriptor( From 735ca3bfa6f56a146d33c67d8db68d2094787054 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 27 Mar 2019 16:18:08 +0200 Subject: [PATCH 39/55] Refactor conditional filter line in searchUtils --- app/utils/searchUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index a08ccd6d1..809b1c9e7 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -19,7 +19,7 @@ function getFetchParamsFromFilters(filters) { ), { purpose: filters.purpose === 'all' ? '' : filters.purpose }, { page: filters.page || 1 }, - { ...(filters.orderBy ? { order_by: filters.orderBy } : {}) }, + filters.orderBy && { order_by: filters.orderBy }, ); return omit(all, 'date', 'duration', 'useTimeRange'); } From 3b7f030ca5cd743b74a5cfbd3bf4a161f82a4892 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 27 Mar 2019 16:21:12 +0200 Subject: [PATCH 40/55] Remove unused block from search reducer --- app/state/reducers/ui/searchReducer.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index e9d60e9e2..4eb4ec17b 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -41,18 +41,6 @@ function searchReducer(state = initialState, action) { }); } - case types.API.SORT_RESULTS_GET_SUCCESS: { - const results = Object.keys(action.payload.entities.resources || {}); - const paginatedResources = Object.values(action.payload.entities.paginatedResources || {}); - const resultCount = paginatedResources.length ? paginatedResources[0].count : 0; - return state.merge({ - resultCount, - results, - searchDone: true, - unitId: null, - }); - } - case types.UI.CHANGE_SEARCH_FILTERS: { const filters = pickSupportedFilters(action.payload); return state.merge({ filters }, { deep: true }); From 377e112b500168008dbc25c4443d93e2ec4ce448 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Wed, 27 Mar 2019 16:22:58 +0200 Subject: [PATCH 41/55] Remove unused action from actions --- app/actions/sortActions.js | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 app/actions/sortActions.js diff --git a/app/actions/sortActions.js b/app/actions/sortActions.js deleted file mode 100644 index cbdb5c495..000000000 --- a/app/actions/sortActions.js +++ /dev/null @@ -1,36 +0,0 @@ - -import types from 'constants/ActionTypes'; - -import { RSAA } from 'redux-api-middleware'; - -import schemas from 'store/middleware/Schemas'; -import { - buildAPIUrl, - getErrorTypeDescriptor, - getHeadersCreator, - getRequestTypeDescriptor, - getSuccessTypeDescriptor, -} from 'utils/apiUtils'; - -function sortResources(orderBy) { - return { - [RSAA]: { - types: [ - getRequestTypeDescriptor(types.API.SORT_RESULTS_GET_REQUEST), - getSuccessTypeDescriptor( - types.API.SORT_RESULTS_GET_SUCCESS, - { schema: schemas.paginatedResourcesSchema } - ), - getErrorTypeDescriptor(types.API.SORT_RESULTS_GET_ERROR), - ], - endpoint: buildAPIUrl(`resource/?order_by=${orderBy}`), - method: 'GET', - headers: getHeadersCreator(), - bailout: state => !state.api.shouldFetch.resources, - }, - }; -} - -export { - sortResources, -}; From 5ed920aeb4c8c1040cad5c21d14cd8c7009d3638 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Fri, 29 Mar 2019 11:18:23 +0200 Subject: [PATCH 42/55] Update offset in input props, follow naming pattern --- app/pages/search/SearchPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index b8cc8f923..ea44d8527 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -109,7 +109,7 @@ class UnconnectedSearchPage extends Component { - + this.sortBy(filters)} /> From 210735afa574afe415766e48284a1ea8b580cbd8 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Fri, 29 Mar 2019 12:11:21 +0200 Subject: [PATCH 43/55] Add some space at top of sort control label --- app/pages/search/SearchPage.js | 2 +- app/pages/search/_search-page.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index ea44d8527..f7dfcf18b 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -108,7 +108,7 @@ class UnconnectedSearchPage extends Component { )} - + this.sortBy(filters)} /> diff --git a/app/pages/search/_search-page.scss b/app/pages/search/_search-page.scss index 45ce5647f..c1c94757b 100644 --- a/app/pages/search/_search-page.scss +++ b/app/pages/search/_search-page.scss @@ -13,6 +13,10 @@ position: relative; } + &__sortControlRow { + margin-top: 10px; + } + .app-MapToggle { background-color: $hel-copper; display: block; From dc6e4eb7a70e368a109fb4a23652f9fdcfbc172b Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Wed, 3 Apr 2019 15:45:05 +0300 Subject: [PATCH 44/55] update translations --- app/i18n/messages/en.json | 8 +++++--- app/i18n/messages/fi.json | 8 +++++--- app/i18n/messages/sv.json | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/i18n/messages/en.json b/app/i18n/messages/en.json index 819aed96e..9f505c9a3 100644 --- a/app/i18n/messages/en.json +++ b/app/i18n/messages/en.json @@ -257,9 +257,11 @@ "SearchControlsContainer.unitLabel": "Premise", "SearchPage.title": "Search", "ShowResourcesLink.text": "Show all premises and equipment", - "SideNavbar.close": "Close", - "SideNavbar.toggle": "Guest", "SortBy.label": "Sort By:", + "SortBy.name.label": "Name", + "SortBy.type.label": "Type", + "SortBy.premise.label": "Premise", + "SortBy.people.label": "People", "TestSiteMessage.text": "This is the test version of Varaamo", "TimeRangeControl.timeRangeTitle": "Time range and minimum duration", "TimeRangeControl.title": "{date} at {start}-{end} {hours}h booking", @@ -282,4 +284,4 @@ "UserReservationsPage.regularEmptyMessage": "No standard reservations", "UserReservationsPage.regularReservationsHeader": "Standard reservations", "UserReservationsPage.title": "My reservations" -} \ No newline at end of file +} diff --git a/app/i18n/messages/fi.json b/app/i18n/messages/fi.json index 0ffee8f1f..34a6981eb 100644 --- a/app/i18n/messages/fi.json +++ b/app/i18n/messages/fi.json @@ -257,9 +257,11 @@ "SearchControlsContainer.unitLabel": "Toimipiste", "SearchPage.title": "Haku", "ShowResourcesLink.text": "Näytä kaikki tilat ja laitteet", - "SideNavbar.close": "Sulje", - "SideNavbar.toggle": "Vieras", "SortBy.label": "Järjestä:", + "SortBy.name.label": "Nimi", + "SortBy.type.label": "Tyyppi", + "SortBy.premise.label": "Toimipiste", + "SortBy.people.label": "Henkilömäärä", "TimeRangeControl.timeRangeTitle": "Käytä aikaväliä ja varauksen minimipituutta", "TimeRangeControl.title": "{date} klo {start}-{end} {hours}h varaus", "TestSiteMessage.text": "Tämä on Varaamon testiversio", @@ -282,4 +284,4 @@ "UserReservationsPage.regularEmptyMessage": "Ei tavallisia varauksia näytettäväksi.", "UserReservationsPage.regularReservationsHeader": "Tavalliset varaukset", "UserReservationsPage.title": "Omat varaukset" -} \ No newline at end of file +} diff --git a/app/i18n/messages/sv.json b/app/i18n/messages/sv.json index e69bdc866..5e018021c 100644 --- a/app/i18n/messages/sv.json +++ b/app/i18n/messages/sv.json @@ -259,9 +259,11 @@ "SearchControlsContainer.unitLabel": "Utrymmet", "SearchPage.title": "Sök", "ShowResourcesLink.text": "Visa alla utrymmen och apparater", - "SideNavbar.close": "Stäng", - "SideNavbar.toggle": "Gäst", "SortBy.label": "Sortera efter:", + "SortBy.name.label": "Namn", + "SortBy.type.label": "Typ", + "SortBy.premise.label": "Lokal", + "SortBy.people.label": "Antal personer", "TestSiteMessage.text": "Detta är Varaamo testversion", "TimeRangeControl.timeRangeTitle": "Tidsurval och minsta reserveringstid", "TimeRangeControl.title": "{date} kl. {start}-{end} {hours}h bokning", @@ -284,4 +286,4 @@ "UserReservationsPage.regularEmptyMessage": "Det finns inga vanliga bokningar att visa.", "UserReservationsPage.regularReservationsHeader": "Vanliga bokningar", "UserReservationsPage.title": "Mina bokningar" -} \ No newline at end of file +} From 6d00b42169b55c59ed74f95e3b49ca030f1846c5 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Wed, 3 Apr 2019 15:55:16 +0300 Subject: [PATCH 45/55] invoke language change on sort option --- app/constants/AppConstants.js | 2 +- app/pages/search/Sort.js | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/constants/AppConstants.js b/app/constants/AppConstants.js index 6bf39377a..a9b1c570f 100644 --- a/app/constants/AppConstants.js +++ b/app/constants/AppConstants.js @@ -69,7 +69,7 @@ export default { TIME_SLOT_DEFAULT_LENGTH: 30, TRACKING: SETTINGS.TRACKING, SORT_BY_OPTIONS: { - RESOURCE_NAME: 'resource_name_lang', + NAME: 'resource_name_lang', TYPE: 'type_name_lang', PREMISES: 'unit_name_lang', PEOPLE: 'people_capacity', diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 3af8f4cde..9203fe588 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -8,17 +8,10 @@ import SelectControl from './controls/SelectControl'; export class UnconnectedSort extends Component { constructor(props) { - super(); + super(props); this.state = { selected: '', }; - const { lang } = props; - this.sortOptions = [ - { label: 'Name', value: CONSTANTS.SORT_BY_OPTIONS.RESOURCE_NAME.replace('lang', lang) }, - { label: 'Type', value: CONSTANTS.SORT_BY_OPTIONS.TYPE.replace('lang', lang) }, - { label: 'Premises', value: CONSTANTS.SORT_BY_OPTIONS.PREMISES.replace('lang', lang) }, - { label: 'People', value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }, - ]; } handleChange = ({ value }) => { @@ -27,6 +20,17 @@ export class UnconnectedSort extends Component { this.props.sortBy(filters); } + getSortOptions = () => { + const { lang, t } = this.props; + + return [ + { label: t('SortBy.name.label'), value: CONSTANTS.SORT_BY_OPTIONS.NAME.replace('lang', lang) }, + { label: t('SortBy.type.label'), value: CONSTANTS.SORT_BY_OPTIONS.TYPE.replace('lang', lang) }, + { label: t('SortBy.premise.label'), value: CONSTANTS.SORT_BY_OPTIONS.PREMISES.replace('lang', lang) }, + { label: t('SortBy.people.label'), value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }, + ]; + } + render() { return ( ); From 6ec92956c7b5daca52fea649bdfd123c8c3c6d4c Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Thu, 4 Apr 2019 14:56:20 +0300 Subject: [PATCH 46/55] refactor sort component --- app/constants/AppConstants.js | 1 + app/pages/search/SearchPage.js | 8 ++++---- app/pages/search/Sort.js | 12 +++--------- app/pages/search/Sort.spec.js | 5 +++-- app/state/reducers/ui/searchReducer.js | 1 + 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/app/constants/AppConstants.js b/app/constants/AppConstants.js index a9b1c570f..d8c11f3ea 100644 --- a/app/constants/AppConstants.js +++ b/app/constants/AppConstants.js @@ -57,6 +57,7 @@ export default { end: '', lat: '', lon: '', + orderBy: '', page: 1, people: '', purpose: '', diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index f7dfcf18b..63bbdd535 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -24,6 +24,7 @@ class UnconnectedSearchPage extends Component { constructor(props) { super(props); this.searchResources = this.searchResources.bind(this); + this.sortResource = this.sortResource.bind(this); } componentDidMount() { @@ -72,9 +73,8 @@ class UnconnectedSearchPage extends Component { this.props.actions.searchResources({ ...filters, ...position }); } - sortBy(newFilters = {}) { - const page = 1; - const filters = { ...this.props.filters, ...newFilters, page }; + sortResource(value) { + const filters = { ...this.props.filters, ...{ orderBy: value } }; this.props.history.push(`/search?${queryString.stringify(filters)}`); } @@ -110,7 +110,7 @@ class UnconnectedSearchPage extends Component { - this.sortBy(filters)} /> +
diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 9203fe588..0fb523e0a 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -14,12 +14,6 @@ export class UnconnectedSort extends Component { }; } - handleChange = ({ value }) => { - const filters = {}; - filters.orderBy = value; - this.props.sortBy(filters); - } - getSortOptions = () => { const { lang, t } = this.props; @@ -34,10 +28,10 @@ export class UnconnectedSort extends Component { render() { return ( this.props.onChange(value)} options={this.getSortOptions()} value={this.state.selected} /> @@ -58,5 +52,5 @@ export default connect( UnconnectedSort.propTypes = { lang: PropTypes.string.isRequired, t: PropTypes.func.isRequired, - sortBy: PropTypes.func.isRequired + onChange: PropTypes.func.isRequired }; diff --git a/app/pages/search/Sort.spec.js b/app/pages/search/Sort.spec.js index ecabe81d2..305831083 100644 --- a/app/pages/search/Sort.spec.js +++ b/app/pages/search/Sort.spec.js @@ -1,10 +1,11 @@ +import CONSTANTS from 'constants/AppConstants'; + import React from 'react'; import simple from 'simple-mock'; import { shallow } from 'enzyme'; import SelectControl from './controls/SelectControl'; import { UnconnectedSort as Sort } from './Sort'; -import CONSTANTS from '../../constants/AppConstants'; describe('pages/search/Sort', () => { const defaultProps = { @@ -21,7 +22,7 @@ describe('pages/search/Sort', () => { const wrapper = getWrapper({}); const selectControl = wrapper.find(SelectControl); expect(selectControl).toHaveLength(1); - expect(selectControl.prop('id')).toBe('sort'); + expect(selectControl.prop('id')).toBe('app-Sort'); expect(selectControl.prop('label')).toBeDefined(); expect(selectControl.prop('onChange')).toBeDefined(); expect(selectControl.prop('value')).toBeDefined(); diff --git a/app/state/reducers/ui/searchReducer.js b/app/state/reducers/ui/searchReducer.js index 4eb4ec17b..17ccfbc6a 100644 --- a/app/state/reducers/ui/searchReducer.js +++ b/app/state/reducers/ui/searchReducer.js @@ -17,6 +17,7 @@ const initialState = Immutable({ start: '', end: '', useTimeRange: false, + orderBy: '', }, page: 1, position: null, From f06092e9c8e5935526b590cc9baf3a33edd301b0 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Thu, 4 Apr 2019 15:39:58 +0300 Subject: [PATCH 47/55] fix unit tests, add more unit tests --- app/pages/search/SearchPage.js | 3 +- app/pages/search/SearchPage.spec.js | 7 ++-- app/pages/search/Sort.js | 12 ++---- app/pages/search/Sort.spec.js | 37 +++++++++++-------- app/state/reducers/ui/searchReducer.spec.js | 1 + .../__tests__/uiSearchFiltersSelector.spec.js | 1 + .../urlSearchFiltersSelector.spec.js | 1 + app/utils/searchUtils.js | 1 - 8 files changed, 34 insertions(+), 29 deletions(-) diff --git a/app/pages/search/SearchPage.js b/app/pages/search/SearchPage.js index 63bbdd535..659fc1ae4 100644 --- a/app/pages/search/SearchPage.js +++ b/app/pages/search/SearchPage.js @@ -90,6 +90,7 @@ class UnconnectedSearchPage extends Component { searchDone, selectedUnitId, showMap, + filters, t, } = this.props; return ( @@ -110,7 +111,7 @@ class UnconnectedSearchPage extends Component { - +
diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index 031465b42..875a618b1 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -94,7 +94,7 @@ describe('pages/search/SearchPage', () => { test('renders a Sort component with correct props', () => { const sort = getWrapper().find(Sort); expect(sort).toHaveLength(1); - expect(typeof sort.prop('sortBy')).toBe('function'); + expect(typeof sort.prop('onChange')).toBe('function'); }); describe('SearchResults', () => { @@ -226,7 +226,7 @@ describe('pages/search/SearchPage', () => { }); }); - describe('sortBy', () => { + describe('sortResource', () => { const pushMock = simple.mock(); beforeAll(() => { const instance = getWrapper( @@ -234,8 +234,9 @@ describe('pages/search/SearchPage', () => { history: { push: pushMock } } ).instance(); - instance.sortBy({ orderBy: 'name' }); + instance.sortResource('name'); }); + test('changes history with correct queryString', () => { expect(pushMock.callCount).toBe(1); expect(pushMock.lastCall.args[0]).toEqual( diff --git a/app/pages/search/Sort.js b/app/pages/search/Sort.js index 0fb523e0a..3c06a5cc1 100644 --- a/app/pages/search/Sort.js +++ b/app/pages/search/Sort.js @@ -7,13 +7,6 @@ import CONSTANTS from '../../constants/AppConstants'; import SelectControl from './controls/SelectControl'; export class UnconnectedSort extends Component { - constructor(props) { - super(props); - this.state = { - selected: '', - }; - } - getSortOptions = () => { const { lang, t } = this.props; @@ -33,7 +26,7 @@ export class UnconnectedSort extends Component { label={this.props.t('SortBy.label')} onChange={({ value }) => this.props.onChange(value)} options={this.getSortOptions()} - value={this.state.selected} + value={this.props.sortValue} /> ); } @@ -52,5 +45,6 @@ export default connect( UnconnectedSort.propTypes = { lang: PropTypes.string.isRequired, t: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired + onChange: PropTypes.func.isRequired, + sortValue: PropTypes.string, }; diff --git a/app/pages/search/Sort.spec.js b/app/pages/search/Sort.spec.js index 305831083..e0bedef0d 100644 --- a/app/pages/search/Sort.spec.js +++ b/app/pages/search/Sort.spec.js @@ -1,5 +1,3 @@ -import CONSTANTS from 'constants/AppConstants'; - import React from 'react'; import simple from 'simple-mock'; import { shallow } from 'enzyme'; @@ -9,33 +7,42 @@ import { UnconnectedSort as Sort } from './Sort'; describe('pages/search/Sort', () => { const defaultProps = { - t: () => 'label', + sortValue: '', + t: value => value, lang: 'en', - sortBy: () => 'people' + onChange: () => {}, }; + + const mockOptions = [ + { + label: 'Name', + value: 'resource_name_en', + } + ]; + function getWrapper(props) { return shallow(); } - describe('render', () => { + describe('pages/search/Sort', () => { test('renders SelectControl for sort with correct props', () => { const wrapper = getWrapper({}); const selectControl = wrapper.find(SelectControl); expect(selectControl).toHaveLength(1); expect(selectControl.prop('id')).toBe('app-Sort'); - expect(selectControl.prop('label')).toBeDefined(); + expect(selectControl.prop('label')).toEqual('SortBy.label'); expect(selectControl.prop('onChange')).toBeDefined(); - expect(selectControl.prop('value')).toBeDefined(); + expect(selectControl.prop('options')).toBeDefined(); + expect(selectControl.prop('value')).toEqual(defaultProps.sortValue); }); - }); - describe('handleChange', () => { - test('calls this.props.onChange with correct value', () => { - const sortBy = simple.mock(); - const instance = getWrapper({ sortBy }).instance(); - instance.handleChange({ value: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }); - expect(sortBy.callCount).toBe(1); - expect(sortBy.lastCall.args[0]).toEqual({ orderBy: CONSTANTS.SORT_BY_OPTIONS.PEOPLE }); + test('get translated options base on language', () => { + const wrapper = getWrapper({ lang: 'foo' }); + const options = wrapper.prop('options'); + + expect(options.length).toEqual(4); + expect(options[0].value).toContain('foo'); + expect(options[3].value).not.toContain('foo'); }); }); }); diff --git a/app/state/reducers/ui/searchReducer.spec.js b/app/state/reducers/ui/searchReducer.spec.js index 6ad44003b..63556e6ab 100644 --- a/app/state/reducers/ui/searchReducer.spec.js +++ b/app/state/reducers/ui/searchReducer.spec.js @@ -180,6 +180,7 @@ describe('state/reducers/ui/searchReducer', () => { search: '', start: '', useTimeRange: false, + orderBy: '' }; const action = clearSearchResults(); const initialState = Immutable({ filters }); diff --git a/app/state/selectors/__tests__/uiSearchFiltersSelector.spec.js b/app/state/selectors/__tests__/uiSearchFiltersSelector.spec.js index 711ee2eab..9e445e52d 100644 --- a/app/state/selectors/__tests__/uiSearchFiltersSelector.spec.js +++ b/app/state/selectors/__tests__/uiSearchFiltersSelector.spec.js @@ -20,6 +20,7 @@ function getState(date = '2015-10-10', start = '08:30', freeOfCharge = '') { start, unit: '', useTimeRange: false, + orderBy: '' }, }, }, diff --git a/app/state/selectors/__tests__/urlSearchFiltersSelector.spec.js b/app/state/selectors/__tests__/urlSearchFiltersSelector.spec.js index 4208ba35d..eaa00a0a8 100644 --- a/app/state/selectors/__tests__/urlSearchFiltersSelector.spec.js +++ b/app/state/selectors/__tests__/urlSearchFiltersSelector.spec.js @@ -17,6 +17,7 @@ describe('Selector: urlSearchFiltersSelector', () => { unit: '', useTimeRange: false, municipality: '', + orderBy: '' }; const getProps = ( diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index 809b1c9e7..4a2bc2ff3 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -19,7 +19,6 @@ function getFetchParamsFromFilters(filters) { ), { purpose: filters.purpose === 'all' ? '' : filters.purpose }, { page: filters.page || 1 }, - filters.orderBy && { order_by: filters.orderBy }, ); return omit(all, 'date', 'duration', 'useTimeRange'); } From fd2065ec309ebf05ec0965b42b676a17c104cf58 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Thu, 4 Apr 2019 15:45:56 +0300 Subject: [PATCH 48/55] fix typo, revert unnecessary file change --- app/pages/search/Sort.spec.js | 8 -------- app/utils/searchUtils.js | 3 ++- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/pages/search/Sort.spec.js b/app/pages/search/Sort.spec.js index e0bedef0d..45b33bad6 100644 --- a/app/pages/search/Sort.spec.js +++ b/app/pages/search/Sort.spec.js @@ -1,5 +1,4 @@ import React from 'react'; -import simple from 'simple-mock'; import { shallow } from 'enzyme'; import SelectControl from './controls/SelectControl'; @@ -13,13 +12,6 @@ describe('pages/search/Sort', () => { onChange: () => {}, }; - const mockOptions = [ - { - label: 'Name', - value: 'resource_name_en', - } - ]; - function getWrapper(props) { return shallow(); } diff --git a/app/utils/searchUtils.js b/app/utils/searchUtils.js index 4a2bc2ff3..6360716b3 100644 --- a/app/utils/searchUtils.js +++ b/app/utils/searchUtils.js @@ -18,8 +18,9 @@ function getFetchParamsFromFilters(filters) { filters.duration ), { purpose: filters.purpose === 'all' ? '' : filters.purpose }, - { page: filters.page || 1 }, + { page: filters.page || 1 } ); + return omit(all, 'date', 'duration', 'useTimeRange'); } From 7b24b5898b08b1b13e54ed74bf23414e914d8251 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Thu, 4 Apr 2019 15:48:47 +0300 Subject: [PATCH 49/55] fix unit test --- app/pages/search/SearchPage.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/pages/search/SearchPage.spec.js b/app/pages/search/SearchPage.spec.js index 875a618b1..718aaebba 100644 --- a/app/pages/search/SearchPage.spec.js +++ b/app/pages/search/SearchPage.spec.js @@ -239,9 +239,7 @@ describe('pages/search/SearchPage', () => { test('changes history with correct queryString', () => { expect(pushMock.callCount).toBe(1); - expect(pushMock.lastCall.args[0]).toEqual( - '/search?date=2015-10-10&orderBy=name&page=1&purpose=some-purpose' - ); + expect(pushMock.lastCall.args[0]).toContain('name'); }); }); From b533ebe00bafbe82258190d1345d180dc5640edf Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Fri, 5 Apr 2019 13:53:28 +0300 Subject: [PATCH 50/55] Add swedish translation in browser warning message --- app/pages/browser-warning/BrowserWarning.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/pages/browser-warning/BrowserWarning.js b/app/pages/browser-warning/BrowserWarning.js index 4124e949b..fb4e70e04 100644 --- a/app/pages/browser-warning/BrowserWarning.js +++ b/app/pages/browser-warning/BrowserWarning.js @@ -25,6 +25,17 @@ function BrowserWarning() { Edge ).

+

+ Varaamo fungerar inte längre med Internet Explorer 11. + Vi arbetar med att lösa problemet. + Under tiden så var vänlig och använd någon annan browser (t.ex + Chrome + , + Firefox + eller + Edge + ). +

); } From e44afcd112e35cd4307d1fceb31cf7bace100914 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Fri, 5 Apr 2019 13:57:12 +0300 Subject: [PATCH 51/55] Update test for browser warning component --- app/pages/browser-warning/BrowserWarning.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pages/browser-warning/BrowserWarning.spec.js b/app/pages/browser-warning/BrowserWarning.spec.js index adbbf0903..25aabf17e 100644 --- a/app/pages/browser-warning/BrowserWarning.spec.js +++ b/app/pages/browser-warning/BrowserWarning.spec.js @@ -15,11 +15,11 @@ describe('pages/browser-warning/BrowserWarning', () => { test('renders a browser warning paragraph', () => { const p = getWrapper().find('p'); - expect(p.length).toBe(2); + expect(p.length).toBe(3); }); test('renders all specified browser links', () => { const a = getWrapper().find('a'); - expect(a.length).toBe(6); + expect(a.length).toBe(9); }); }); From 3930658b6bd5265fd22eef108c30d793eca730d7 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 9 Apr 2019 12:06:36 +0300 Subject: [PATCH 52/55] Add unit test for index file rendering browser warning component --- app/index.spec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 app/index.spec.js diff --git a/app/index.spec.js b/app/index.spec.js new file mode 100644 index 000000000..520200cc5 --- /dev/null +++ b/app/index.spec.js @@ -0,0 +1,17 @@ +import React from 'react'; + +import BrowserWarning from './pages/browser-warning/BrowserWarning'; +import { shallowWithIntl } from './utils/testUtils'; + +jest.mock('react-device-detect', () => ({ browserName: 'IE' })); + +describe('app/index', () => { + function getWrapper() { + return shallowWithIntl(); + } + + test('renders BrowserWarning component correctly', () => { + const warningComponent = getWrapper(); + expect(warningComponent.length).toBe(1); + }); +}); From 5218988ffabba6b5bf4d1b240b16fa0f0dc98f58 Mon Sep 17 00:00:00 2001 From: Rasbin Rijal Date: Tue, 9 Apr 2019 12:09:10 +0300 Subject: [PATCH 53/55] Update warning info to be more general for Internet Explorer --- app/pages/browser-warning/BrowserWarning.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/pages/browser-warning/BrowserWarning.js b/app/pages/browser-warning/BrowserWarning.js index fb4e70e04..20609b135 100644 --- a/app/pages/browser-warning/BrowserWarning.js +++ b/app/pages/browser-warning/BrowserWarning.js @@ -4,7 +4,7 @@ function BrowserWarning() { return (

- Currently, Varaamo does not support IE11. + Currently, Varaamo does not support Internet Explorer. We are investigating this issue and finding a solution. Meanwhile, use another browser (such as Chrome @@ -15,7 +15,7 @@ function BrowserWarning() { ).

- Varaamo ei tue IE11 selainta tällä hetkellä. + Varaamo ei tue Internet Explorer selainta tällä hetkellä. Selvitämme ongelmaa sen ratkaisemiseksi. Sillä välin, käytä toista selainta (kuten Chrome @@ -26,7 +26,7 @@ function BrowserWarning() { ).

- Varaamo fungerar inte längre med Internet Explorer 11. + Varaamo fungerar inte längre med Internet Explorer. Vi arbetar med att lösa problemet. Under tiden så var vänlig och använd någon annan browser (t.ex Chrome From 9e3130f8313fcde81a6dc3e506edbad8947f1e05 Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Tue, 9 Apr 2019 14:25:48 +0300 Subject: [PATCH 54/55] exclude index.js out of codecov --- app/index.js | 18 +++++++----------- app/index.spec.js | 17 ----------------- jest.config.js | 2 +- 3 files changed, 8 insertions(+), 29 deletions(-) delete mode 100644 app/index.spec.js diff --git a/app/index.js b/app/index.js index 8082ee5b1..18ad32e50 100644 --- a/app/index.js +++ b/app/index.js @@ -24,17 +24,13 @@ const finalState = Immutable(initialStoreState).merge([initialServerState, initi deep: true, }); const store = configureStore(finalState); +const isIEBrowser = browserName === 'IE'; -if (browserName === 'IE') { - render( - , - document.getElementById('root') - ); -} else { - render( +// TODO: Support IE11 in the future. +render(isIEBrowser ? + : ( {getRoutes()} - , - document.getElementById('root') - ); -} + + ), +document.getElementById('root')); diff --git a/app/index.spec.js b/app/index.spec.js deleted file mode 100644 index 520200cc5..000000000 --- a/app/index.spec.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; - -import BrowserWarning from './pages/browser-warning/BrowserWarning'; -import { shallowWithIntl } from './utils/testUtils'; - -jest.mock('react-device-detect', () => ({ browserName: 'IE' })); - -describe('app/index', () => { - function getWrapper() { - return shallowWithIntl(); - } - - test('renders BrowserWarning component correctly', () => { - const warningComponent = getWrapper(); - expect(warningComponent.length).toBe(1); - }); -}); diff --git a/jest.config.js b/jest.config.js index 170e19d0d..a917dc335 100755 --- a/jest.config.js +++ b/jest.config.js @@ -11,7 +11,7 @@ module.exports = { clearMocks: true, // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: ['app/**/*.{js,jsx,mjs}'], + collectCoverageFrom: ['app/**/*.{js,jsx,mjs}', '"!app/index.js"'], // The directory where Jest should output its coverage files coverageDirectory: 'coverage', From 566c67173918d016a0a6643ce0e1d159a7cfec7b Mon Sep 17 00:00:00 2001 From: Chi Nguyen Date: Tue, 9 Apr 2019 15:36:20 +0300 Subject: [PATCH 55/55] Prepare release 0.2.0 --- CHANGELOG.md | 67 +++++++++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b7b84ff..0d77b9a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +* 0.1.2 + ** MAJOR CHANGES ** + + - Add new selection field to sort filtered resources. Currently support to search by name, type, premise, people. + - Temporarily only show warning messages in 3 languages for IE11 user. + - Ability to favourite resources straight on search view instead going to resource detail page. + + ** CHANGELOG ** + + - [#895](https://github.com/City-of-Helsinki/varaamo/pull/895) Add sort to sort filtered resources. + - [#904](https://github.com/City-of-Helsinki/varaamo/pull/904) Favourite Resource on search view. + - [#909](https://github.com/City-of-Helsinki/varaamo/pull/909) Show warning message for IE11 users. + * 0.1.1 ** HOTFIX ** @@ -13,70 +26,70 @@ ** CHANGELOG ** UI changes: - - #863: Make homepage banner clickable. + - [#863](https://github.com/City-of-Helsinki/varaamo/pull/863): Make homepage banner clickable. - - #865: Delayed reservation. + - [#865](https://github.com/City-of-Helsinki/varaamo/pull/865): Delayed reservation. - - #867: Add config to fetch all unit that doesn't have empty resources. + - [#867](https://github.com/City-of-Helsinki/varaamo/pull/867): Add config to fetch all unit that doesn't have empty resources. - - #868: Add municipality filters for filtering resources base on municiples. + - [#868](https://github.com/City-of-Helsinki/varaamo/pull/868): Add municipality filters for filtering resources base on municiples. - - #873: Limit the selection of time slots to the ones within max period. + - [#873](https://github.com/City-of-Helsinki/varaamo/pull/873): Limit the selection of time slots to the ones within max period. - - #875: Expand advanced search panel when filters are applied. + - [#875](https://github.com/City-of-Helsinki/varaamo/pull/875): Expand advanced search panel when filters are applied. - - #876: Free-of-charge filter for resources. + - [#876](https://github.com/City-of-Helsinki/varaamo/pull/876): Free-of-charge filter for resources. - - #878: Remove the link for old website from the footer. + - [#878](https://github.com/City-of-Helsinki/varaamo/pull/878): Remove the link for old website from the footer. - - #883: Clear all filters after reset. + - [#883](https://github.com/City-of-Helsinki/varaamo/pull/883): Clear all filters after reset. - - #889: Disable reservation time limit for admins. + - [#889](https://github.com/City-of-Helsinki/varaamo/pull/889): Disable reservation time limit for admins. - - #899: Add unpublished tag to resource search list. + - [#899](https://github.com/City-of-Helsinki/varaamo/pull/899): Add unpublished tag to resource search list. - - #901: Add navigation links to staff and higher permission user. + - [#901](https://github.com/City-of-Helsinki/varaamo/pull/901): Add navigation links to staff and higher permission user. Upgrading: - - #854: Upgrade react-router to react-router v4. + - [#854](https://github.com/City-of-Helsinki/varaamo/pull/854): Upgrade react-router to react-router v4. - - #856: Add dockerize config to dockerize development environment. + - [#856](https://github.com/City-of-Helsinki/varaamo/pull/856): Add dockerize config to dockerize development environment. - - #857: Upgrade moment, moment-range, moment-timezome. + - [#857](https://github.com/City-of-Helsinki/varaamo/pull/857): Upgrade moment, moment-range, moment-timezome. - - #860: Upgrade lodash. + - [#860](https://github.com/City-of-Helsinki/varaamo/pull/860): Upgrade lodash. - - #862: Replace redux-logger with redux-devtools. + - [#862](https://github.com/City-of-Helsinki/varaamo/pull/862): Replace redux-logger with redux-devtools. - - #868: Upgrade react-select. + - [#868](https://github.com/City-of-Helsinki/varaamo/pull/868): Upgrade react-select. - - #874: Replace React internal prop-types with npm prop-types. + - [#874](https://github.com/City-of-Helsinki/varaamo/pull/874): Replace React internal prop-types with npm prop-types. - - #879: Upgrade React to 15.6.2, Enzyme to v3+. + - [#879](https://github.com/City-of-Helsinki/varaamo/pull/879): Upgrade React to 15.6.2, Enzyme to v3+. - - #882: Upgrade react-day-picker, remove react-date-picker. + - [#882](https://github.com/City-of-Helsinki/varaamo/pull/882): Upgrade react-day-picker, remove react-date-picker. - - #884: Upgrade babel to v7, webpack v4, replace Karma/Mocha/Chai with Jest. + - [#884](https://github.com/City-of-Helsinki/varaamo/pull/884): Upgrade babel to v7, webpack v4, replace Karma/Mocha/Chai with Jest. - - #890: Replace Chai with Jest's assertions. + - [#890](https://github.com/City-of-Helsinki/varaamo/pull/890): Replace Chai with Jest's assertions. - - #892: Remove unnecessary outdated dependencies: + - [#892](https://github.com/City-of-Helsinki/varaamo/pull/892): Remove unnecessary outdated dependencies: - Remove react-document-title, use react-helmet - Remove react-body-classname, classname append can be handled by classnames - - #893: Remove unnessary persisted state library, upgrade redux and dependencies: + - [#893](https://github.com/City-of-Helsinki/varaamo/pull/893): Remove unnessary persisted state library, upgrade redux and dependencies: - Remove redux-localstorage and redux-localstorage-filter. Replaced with vanilla code. - Upgrade redux and dependencies. - - #894: Upgrade React to 16.8.x: + - [#894](https://github.com/City-of-Helsinki/varaamo/pull/894): Upgrade React to 16.8.x: - Upgrade React to 16.8.x - Upgrade React's dependencies to latest. - - #900: Clean up obsolete/deprecated component. + - [#900](https://github.com/City-of-Helsinki/varaamo/pull/900): Clean up obsolete/deprecated component. - Delete navbar, sidebar, side-navbar which was replaced by new component but not getting removed. diff --git a/package.json b/package.json index fae09e1c0..d4e98e234 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "varaamo", - "version": "0.1.1", + "version": "0.2.0", "repository": { "type": "git", "url": "https://github.com/City-of-Helsinki/varaamo"