Repository: kiwicom/mobile
Pull request #1400 (2019-01-04 17:17:38)

Show warning when selected rooms don't have room for everyone
We want to let the user know when he is searching for hotels for 5 persons,
but selects beds for less than 5 persons

Also, we wait for next android release before we merge this feature. It can be deployed rapidly with code-push anyways 😄 


Patch:
diff --git a/app/core/src/screens/hotelsStack/Homepage.js b/app/core/src/screens/hotelsStack/Homepage.js
index 4154ab5c..32a609b0 100644
--- a/app/core/src/screens/hotelsStack/Homepage.js
+++ b/app/core/src/screens/hotelsStack/Homepage.js
@@ -38,7 +38,7 @@ export default class Homepage extends React.Component<Props> {
       currency: 'EUR',
       checkin: DateFormatter(DateUtils().addDays(30)).formatForMachine(),
       checkout: DateFormatter(DateUtils().addDays(36)).formatForMachine(),
-      roomsConfiguration: [{ adultsCount: 1, children: [] }],
+      roomsConfiguration: [{ adultsCount: 3, children: [] }],
     });
 
   goToStay22HotelsPage = () =>
diff --git a/app/hotels/src/singleHotel/bookNow/BookNow.js b/app/hotels/src/singleHotel/bookNow/BookNow.js
index a7b53cd7..cbcf4fd6 100644
--- a/app/hotels/src/singleHotel/bookNow/BookNow.js
+++ b/app/hotels/src/singleHotel/bookNow/BookNow.js
@@ -7,7 +7,7 @@ import {
   withNavigation,
   type NavigationType,
 } from '@kiwicom/mobile-navigation';
-import { DeviceInfo, Translation } from '@kiwicom/mobile-localization';
+import { DeviceInfo, Translation, Alert } from '@kiwicom/mobile-localization';
 
 import convertRooms from './convertRooms';
 import {
@@ -26,6 +26,8 @@ type Props = {
   +navigation: NavigationType,
   +currency: string,
   +hotelId: ?string,
+  +getGuestCount: () => number,
+  +maxPersons: number,
 };
 
 export class BookNow extends React.Component<Props> {
@@ -40,9 +42,38 @@ export class BookNow extends React.Component<Props> {
     }
   };
 
+  onPress = () => {
+    const numberOfGuests = this.props.getGuestCount();
+    if (numberOfGuests > this.props.maxPersons) {
+      Alert.translatedAlert(
+        {
+          id: 'single_hotel.book_now.alert_title',
+        },
+        {
+          id: 'single_hotel.book_now.alert_body',
+          values: { numberOfGuests },
+        },
+        [
+          {
+            text: { id: 'shared.button.cancel' },
+            style: 'destructive',
+          },
+          {
+            text: {
+              id: 'single_hotel.book_now.alert_ok',
+            },
+            onPress: this.handleGoToPayment,
+          },
+        ],
+      );
+    } else {
+      this.handleGoToPayment();
+    }
+  };
+
   render() {
     return (
-      <Button onPress={this.handleGoToPayment} testID="bookNowButton">
+      <Button onPress={this.onPress} testID="bookNowButton">
         <ButtonTitle
           text={<Translation id="single_hotel.book_now" />}
           style={styles.text}
@@ -52,12 +83,17 @@ export class BookNow extends React.Component<Props> {
   }
 }
 
-const select = ({ currency, hotelId }: HotelsContextState) => ({
+const select = ({ currency, hotelId, getGuestCount }: HotelsContextState) => ({
   currency,
   hotelId,
+  getGuestCount,
 });
-const selectHotelDetailScreen = ({ selected }: HotelDetailScreenState) => ({
+const selectHotelDetailScreen = ({
+  selected,
+  maxPersons,
+}: HotelDetailScreenState) => ({
   selected,
+  maxPersons,
 });
 
 export default withHotelDetailScreenContext(selectHotelDetailScreen)(
diff --git a/packages/localization/src/vocabularies/Hotels.js b/packages/localization/src/vocabularies/Hotels.js
index 44ff8639..3095f0d9 100644
--- a/packages/localization/src/vocabularies/Hotels.js
+++ b/packages/localization/src/vocabularies/Hotels.js
@@ -73,6 +73,10 @@ export default {
   'single_hotel.book_now': 'Book Now',
   'single_hotel.book_now.description':
     '__1_personCount__ Guests · __2_numberOfRooms__ Rooms',
+  'single_hotel.book_now.alert_title': 'Not enough beds for everyone',
+  'single_hotel.book_now.alert_body':
+    'Your selection accommodates less than __numberOfGuests__ persons',
+  'single_hotel.book_now.alert_ok': "Thats's fine",
   'single_hotel.description.facilities.show_less': 'Show less',
   'single_hotel.description.facilities.show_more': 'More',
   'single_hotel.hotel_detail_screen.hotel_not_found': 'Hotel not found.',


Test patch:
diff --git a/app/hotels/src/singleHotel/bookNow/__tests__/BookNow.test.js b/app/hotels/src/singleHotel/bookNow/__tests__/BookNow.test.js
index 2fb8c8fc..ac8e2028 100644
--- a/app/hotels/src/singleHotel/bookNow/__tests__/BookNow.test.js
+++ b/app/hotels/src/singleHotel/bookNow/__tests__/BookNow.test.js
@@ -2,6 +2,7 @@
 
 import * as React from 'react';
 import { PlaygroundRenderer } from '@kiwicom/mobile-playground';
+import { Alert } from '@kiwicom/mobile-localization';
 
 import { BookNow } from '../BookNow';
 
@@ -41,6 +42,8 @@ it('renders without crashing', () => {
     checkout: new Date(1),
     currency: 'EUR',
     navigation,
+    getGuestCount: jest.fn(),
+    maxPersons: 2,
   };
   PlaygroundRenderer.render(<BookNow {...props} />);
 });
@@ -57,7 +60,39 @@ it('renders without crashing with missing data', () => {
     checkout: new Date(1),
     currency: 'EUR',
     navigation,
+    getGuestCount: jest.fn(),
+    maxPersons: 2,
   };
 
   PlaygroundRenderer.render(<BookNow {...props} />);
 });
+
+it('calls handleGoToPayment when numberOfGuests = maxPersons', () => {
+  // $FlowExpectedError: Passing just props needed to run test
+  const Component = new BookNow({
+    getGuestCount: () => 5,
+    maxPersons: 5,
+  });
+
+  const handleGoToPayment = jest.fn();
+  Component.handleGoToPayment = handleGoToPayment;
+  Component.onPress();
+
+  expect(handleGoToPayment).toHaveBeenCalled();
+});
+
+it('should show an alert if numberOfGuests > maxPersons', () => {
+  // $FlowExpectedError: Passing just props needed to run test
+  const Component = new BookNow({
+    getGuestCount: () => 6,
+    maxPersons: 5,
+  });
+
+  const spy = jest.spyOn(Alert, 'translatedAlert');
+  const handleGoToPayment = jest.fn();
+  Component.handleGoToPayment = handleGoToPayment;
+  Component.onPress();
+
+  expect(handleGoToPayment).not.toHaveBeenCalled();
+  expect(spy).toHaveBeenCalled();
+});