Repository: kiwicom/mobile
Pull request #1301 (2018-11-08 11:31:32)

Hotels: Replace idx with optional chaining in allHotels folder


Patch:
diff --git a/app/hotels/src/allHotels/AllHotelsSearchList.js b/app/hotels/src/allHotels/AllHotelsSearchList.js
index e56208a2..2faa3443 100644
--- a/app/hotels/src/allHotels/AllHotelsSearchList.js
+++ b/app/hotels/src/allHotels/AllHotelsSearchList.js
@@ -4,7 +4,6 @@ import * as React from 'react';
 import { GeneralError } from '@kiwicom/mobile-shared';
 import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
 import { Translation } from '@kiwicom/mobile-localization';
-import idx from 'idx';
 
 import AllHotelsSearchRow from './AllHotelsSearchRow';
 import type { AllHotelsSearchList as AllHotelsSearchListProps } from './__generated__/AllHotelsSearchList.graphql';
@@ -16,13 +15,15 @@ type PropsWithContext = {|
 |};
 
 export class AllHotelsSearchList extends React.Component<PropsWithContext> {
-  componentDidMount = () => {
-    const hotelId = idx(this.props.data, _ => _[0].hotelId);
+  componentDidMount() {
+    const hotelId = this.props.data?.[0]?.hotelId;
+
     if (hotelId != null) {
       this.props.setHotelId(hotelId);
     }
-  };
-  render = () => {
+  }
+
+  render() {
     const hotels = this.props.data || [];
 
     if (hotels.length === 0) {
@@ -39,14 +40,14 @@ export class AllHotelsSearchList extends React.Component<PropsWithContext> {
       <React.Fragment>
         {hotels.map((hotel, index) => (
           <AllHotelsSearchRow
-            key={idx(hotel, _ => _.id)}
+            key={hotel?.id}
             data={hotel}
             testID={index === 0 ? 'firstHotelResult' : ''}
           />
         ))}
       </React.Fragment>
     );
-  };
+  }
 }
 
 type Props = {|
diff --git a/app/hotels/src/allHotels/HotelDistance.js b/app/hotels/src/allHotels/HotelDistance.js
index e80e9027..90d1d85a 100644
--- a/app/hotels/src/allHotels/HotelDistance.js
+++ b/app/hotels/src/allHotels/HotelDistance.js
@@ -1,10 +1,9 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
 import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
 import { StyleSheet, Text } from '@kiwicom/mobile-shared';
 import { Translation } from '@kiwicom/mobile-localization';
-import idx from 'idx';
 import { defaultTokens } from '@kiwicom/mobile-orbit';
 
 import type { HotelDistance_hotel } from './__generated__/HotelDistance_hotel.graphql';
@@ -17,51 +16,62 @@ type Props = {|
 const CITY_CENTER_RADIUS = 1.5;
 
 function HotelDistance({ hotel }: Props) {
-  const distance = idx(hotel, _ => _.distanceFromCenter) || null;
+  const distance = hotel?.distanceFromCenter ?? null;
+
   if (distance === null) {
     return null;
   }
 
   return (
     <Text style={style.text}>
-      <Translation
-        passThrough={getDistanceText(distance, CITY_CENTER_RADIUS)}
-      />
+      {getDistanceText(distance, CITY_CENTER_RADIUS)}
     </Text>
   );
 }
 
-const style = StyleSheet.create({
-  text: {
-    letterSpacing: 0.2,
-    color: defaultTokens.colorTextSecondary,
-    fontSize: 12,
-    lineHeight: 15,
-  },
-});
-
 export function getDistanceText(
   distanceFromCenter: number,
   cityCenterRadius: number,
 ) {
   const distanceFromCityCenter = distanceFromCenter - cityCenterRadius;
-  let distanceText = '';
+  let distanceText = <Translation passThrough="" />;
 
   if (distanceFromCenter <= cityCenterRadius) {
-    distanceText = 'In the city center';
+    distanceText = (
+      <Translation id="hotels_search.hotel_distance.in_city_center" />
+    );
   } else if (distanceFromCityCenter < 1) {
     // 1 km from city center radius shows in meters
     // Round up to 100 m
     const distanceInMeters = distanceFromCityCenter * 1000;
     const roundedDistanceInMeters = 100 * Math.ceil(distanceInMeters / 100);
-    distanceText = `${roundedDistanceInMeters}m from center`;
+    distanceText = (
+      <Translation
+        id="hotels_search.hotel_distance.meters_from_center"
+        values={{ distance: roundedDistanceInMeters }}
+      />
+    );
   } else {
-    distanceText = `${distanceFromCityCenter.toFixed(1)}km from center`;
+    distanceText = (
+      <Translation
+        id="hotels_search.hotel_distance.kilo_meters_from_center"
+        values={{ distance: distanceFromCityCenter.toFixed(1) }}
+      />
+    );
   }
 
   return distanceText;
 }
 
+const style = StyleSheet.create({
+  text: {
+    letterSpacing: 0.2,
+    color: defaultTokens.colorTextSecondary,
+    fontSize: 12,
+    lineHeight: 15,
+  },
+});
+
 export default createFragmentContainer(
   HotelDistance,
   graphql`
diff --git a/app/hotels/src/allHotels/HotelTitle.js b/app/hotels/src/allHotels/HotelTitle.js
index 8825ddc3..57b5147c 100644
--- a/app/hotels/src/allHotels/HotelTitle.js
+++ b/app/hotels/src/allHotels/HotelTitle.js
@@ -1,7 +1,6 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
-import idx from 'idx';
 import { View } from 'react-native';
 import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
 import { Price, Stars, Text, StyleSheet } from '@kiwicom/mobile-shared';
@@ -16,15 +15,13 @@ type Props = {|
 |};
 
 function HotelTitle({ data }: Props) {
-  const hotelName = idx(data, _ => _.name);
-  const hotelStars = idx(data, _ => _.rating.stars);
-
-  const price = data.price || null;
+  const hotelName = data.name ?? '';
+  const hotelStars = data.rating?.stars;
 
   return (
     <React.Fragment>
       <Text style={style.title}>
-        <Translation passThrough={`${hotelName || ''} `} />
+        <Translation passThrough={`${hotelName} `} />
         <Text style={style.rating}>
           <Stars rating={hotelStars} />
         </Text>
@@ -33,7 +30,7 @@ function HotelTitle({ data }: Props) {
       <View style={style.distance}>
         <Distance hotel={data} />
       </View>
-      <Price price={price} style={style.price} />
+      <Price price={data.price} style={style.price} />
     </React.Fragment>
   );
 }
diff --git a/app/hotels/src/allHotels/HotelsPaginationContainer.js b/app/hotels/src/allHotels/HotelsPaginationContainer.js
index 0799b0e2..efb16640 100644
--- a/app/hotels/src/allHotels/HotelsPaginationContainer.js
+++ b/app/hotels/src/allHotels/HotelsPaginationContainer.js
@@ -7,7 +7,6 @@ import {
   type RelayPaginationProp,
 } from '@kiwicom/mobile-relay';
 import { Logger } from '@kiwicom/mobile-shared';
-import idx from 'idx';
 
 import type { HotelsPaginationContainer as HotelsPaginationContainerType } from './__generated__/HotelsPaginationContainer.graphql';
 import HotelsContext from '../HotelsContext';
@@ -35,20 +34,16 @@ export class HotelsPaginationContainer extends React.Component<
     };
   }
 
-  componentDidMount = () => {
+  componentDidMount() {
     Logger.ancillaryDisplayed(
       Logger.Type.ANCILLARY_STEP_RESULTS,
       Logger.Provider.ANCILLARY_PROVIDER_BOOKINGCOM,
     );
 
-    const priceMax = idx(
-      this.props,
-      _ => _.data.allAvailableBookingComHotels.stats.maxPrice,
-    );
-    const priceMin = idx(
-      this.props,
-      _ => _.data.allAvailableBookingComHotels.stats.minPrice,
-    );
+    const priceMax = this.props.data?.allAvailableBookingComHotels?.stats
+      ?.maxPrice;
+    const priceMin = this.props.data?.allAvailableBookingComHotels?.stats
+      ?.minPrice;
 
     if (priceMax != null && priceMin != null) {
       this.props.setCurrentSearchStats({
@@ -56,7 +51,7 @@ export class HotelsPaginationContainer extends React.Component<
         priceMin,
       });
     }
-  };
+  }
 
   loadMore = () => {
     if (this.props.relay.hasMore() && !this.props.relay.isLoading()) {
@@ -68,10 +63,9 @@ export class HotelsPaginationContainer extends React.Component<
     }
   };
 
-  render = () => {
-    const edges =
-      idx(this.props.data, _ => _.allAvailableBookingComHotels.edges) || [];
-    const data = edges.map(hotel => idx(hotel, _ => _.node));
+  render() {
+    const edges = this.props.data?.allAvailableBookingComHotels?.edges ?? [];
+    const data = edges.map(hotel => hotel?.node);
 
     return (
       <RenderSearchResults
@@ -82,7 +76,7 @@ export class HotelsPaginationContainer extends React.Component<
         top={56}
       />
     );
-  };
+  }
 }
 
 type Props = {|
diff --git a/app/hotels/src/allHotels/LoadMoreButton.js b/app/hotels/src/allHotels/LoadMoreButton.js
index af475e99..a12013a8 100644
--- a/app/hotels/src/allHotels/LoadMoreButton.js
+++ b/app/hotels/src/allHotels/LoadMoreButton.js
@@ -1,4 +1,4 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
 import { View } from 'react-native';
diff --git a/app/hotels/src/allHotels/NewAllHotelsSearch.js b/app/hotels/src/allHotels/NewAllHotelsSearch.js
index c5bf6f03..8177b67b 100644
--- a/app/hotels/src/allHotels/NewAllHotelsSearch.js
+++ b/app/hotels/src/allHotels/NewAllHotelsSearch.js
@@ -1,4 +1,4 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
 import { graphql, PublicApiRenderer } from '@kiwicom/mobile-relay';
diff --git a/app/hotels/src/allHotels/Stay22HotelsSearch.js b/app/hotels/src/allHotels/Stay22HotelsSearch.js
index 0c9dcdb3..7694b55c 100644
--- a/app/hotels/src/allHotels/Stay22HotelsSearch.js
+++ b/app/hotels/src/allHotels/Stay22HotelsSearch.js
@@ -1,4 +1,4 @@
-// @flow
+// @flow strict
 
 import * as React from 'react';
 import { graphql, PublicApiRenderer } from '@kiwicom/mobile-relay';
diff --git a/app/hotels/src/allHotels/Stay22PaginationContainer.js b/app/hotels/src/allHotels/Stay22PaginationContainer.js
index 96fb93e5..4c7fe564 100644
--- a/app/hotels/src/allHotels/Stay22PaginationContainer.js
+++ b/app/hotels/src/allHotels/Stay22PaginationContainer.js
@@ -8,7 +8,6 @@ import {
   type RelayPaginationProp,
 } from '@kiwicom/mobile-relay';
 import { Logger } from '@kiwicom/mobile-shared';
-import idx from 'idx';
 
 import type { Stay22PaginationContainer as Stay22PaginationContainerType } from './__generated__/Stay22PaginationContainer.graphql';
 import HotelsContext from '../HotelsContext';
@@ -39,13 +38,13 @@ export class Stay22PaginationContainer extends React.Component<
     };
   }
 
-  componentDidMount = () => {
+  componentDidMount() {
     Logger.ancillaryDisplayed(
       Logger.Type.ANCILLARY_STEP_RESULTS,
       Logger.Provider.ANCILLARY_PROVIDER_STAY22,
     );
     // TODO: Set min max price here when supported by API
-  };
+  }
 
   loadMore = () => {
     if (this.props.relay.hasMore() && !this.props.relay.isLoading()) {
@@ -57,10 +56,9 @@ export class Stay22PaginationContainer extends React.Component<
     }
   };
 
-  render = () => {
-    const edges =
-      idx(this.props.data, _ => _.allAvailableStay22Hotels.edges) || [];
-    const data = edges.map(hotel => idx(hotel, _ => _.node));
+  render() {
+    const edges = this.props.data.allAvailableStay22Hotels?.edges ?? [];
+    const data = edges.map(hotel => hotel?.node);
 
     return (
       <RenderSearchResults
@@ -71,7 +69,7 @@ export class Stay22PaginationContainer extends React.Component<
         top={0}
       />
     );
-  };
+  }
 }
 
 type Props = {|
diff --git a/app/hotels/src/map/allHotels/HotelSwipeItem.js b/app/hotels/src/map/allHotels/HotelSwipeItem.js
index eadc900b..3fff62b1 100644
--- a/app/hotels/src/map/allHotels/HotelSwipeItem.js
+++ b/app/hotels/src/map/allHotels/HotelSwipeItem.js
@@ -33,6 +33,7 @@ export class HotelSwipeItemWithContext extends React.Component<
   PropsWithContext,
 > {
   openSingleHotel = (hotelId: string) => {
+    this.props.setHotelId(hotelId);
     this.props.navigation.navigate('SingleHotel', {
       hotelId,
       checkin: this.props.checkin,
diff --git a/packages/localization/src/vocabularies/Hotels.js b/packages/localization/src/vocabularies/Hotels.js
index d7105a6f..d9691194 100644
--- a/packages/localization/src/vocabularies/Hotels.js
+++ b/packages/localization/src/vocabularies/Hotels.js
@@ -89,6 +89,11 @@ export default {
   'hotels_search.location_picker.header': 'Where',
   'hotels_search.location_picker.recent_search': 'Recent search',
   'hotels_search.header.to': 'to',
+  'hotels_search.hotel_distance.in_city_center': 'In the city center',
+  'hotels_search.hotel_distance.meters_from_center':
+    '__distance__m from center',
+  'hotels_search.hotel_distance.kilo_meters_from_center':
+    '__distance__km from center',
 
   'single_hotel.bedding_info.guests': '__numberOfGuests__ Guests',
   'single_hotel.book_now': 'Book Now',


Test patch:
diff --git a/app/hotels/src/allHotels/__tests__/HotelDistance.test.js b/app/hotels/src/allHotels/__tests__/HotelDistance.test.js
index e01be6fb..afd6e7fb 100644
--- a/app/hotels/src/allHotels/__tests__/HotelDistance.test.js
+++ b/app/hotels/src/allHotels/__tests__/HotelDistance.test.js
@@ -5,14 +5,45 @@ import { getDistanceText } from '../HotelDistance';
 const cityCenterRadius = 1.5;
 
 it('Distance should be in the city center', () => {
-  expect(getDistanceText(1.3, cityCenterRadius)).toBe('In the city center');
+  expect(getDistanceText(1.3, cityCenterRadius)).toMatchInlineSnapshot(`
+<Translation
+  id="hotels_search.hotel_distance.in_city_center"
+/>
+`);
 });
 
 it('Distance should be in meters and rounded up to 100', () => {
-  expect(getDistanceText(1.81, cityCenterRadius)).toBe('400m from center');
-  expect(getDistanceText(1.89, cityCenterRadius)).toBe('400m from center');
+  expect(getDistanceText(1.81, cityCenterRadius)).toMatchInlineSnapshot(`
+<Translation
+  id="hotels_search.hotel_distance.meters_from_center"
+  values={
+    Object {
+      "distance": 400,
+    }
+  }
+/>
+`);
+  expect(getDistanceText(1.89, cityCenterRadius)).toMatchInlineSnapshot(`
+<Translation
+  id="hotels_search.hotel_distance.meters_from_center"
+  values={
+    Object {
+      "distance": 400,
+    }
+  }
+/>
+`);
 });
 
 it('Distance should be in km', () => {
-  expect(getDistanceText(4.81, cityCenterRadius)).toBe('3.3km from center');
+  expect(getDistanceText(4.81, cityCenterRadius)).toMatchInlineSnapshot(`
+<Translation
+  id="hotels_search.hotel_distance.kilo_meters_from_center"
+  values={
+    Object {
+      "distance": "3.3",
+    }
+  }
+/>
+`);
 });