Repository: kiwicom/mobile
Pull request #1007 (2018-08-21 15:38:11)

Insurance Menu Item displayed conditionally; can trigger alert if les…
…s than 48 hours before

RobinCsl: @tbergq 🚀 

Patch:
diff --git a/app/MMB/src/scenes/tripServices/InsuranceMenuItem.js b/app/MMB/src/scenes/tripServices/InsuranceMenuItem.js
deleted file mode 100644
index c950f820..00000000
--- a/app/MMB/src/scenes/tripServices/InsuranceMenuItem.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// @flow strict
-
-import * as React from 'react';
-import { TextIcon } from '@kiwicom/mobile-shared';
-import { Translation } from '@kiwicom/mobile-localization';
-import { TodoMenuItem } from '@kiwicom/mobile-navigation';
-
-type Props = {|
-  onOpenInsurance: () => void,
-|};
-
-export default class InsuranceMenuItem extends React.Component<Props> {
-  render = () => {
-    const insurance = true; // TODO: fetch from the API (at least 48 hours before departure, no US nationality, CONFIRMED status only)
-
-    if (!insurance) {
-      // no lounges available on this trip (do not render the menu item at all)
-      return null;
-    }
-
-    return (
-      <TodoMenuItem
-        title={
-          <Translation id="mmb.trip_services.general_services.insurance" />
-        }
-        icon={<TextIcon code="'" />}
-        onPress={this.props.onOpenInsurance}
-      />
-    );
-  };
-}
diff --git a/app/MMB/src/scenes/tripServices/TripServiceRefreshContainer.js b/app/MMB/src/scenes/tripServices/TripServiceRefreshContainer.js
index 45997cff..c9dffc5a 100644
--- a/app/MMB/src/scenes/tripServices/TripServiceRefreshContainer.js
+++ b/app/MMB/src/scenes/tripServices/TripServiceRefreshContainer.js
@@ -19,7 +19,7 @@ import idx from 'idx';
 import HotelMenuItem from './hotelMenuItem/HotelMenuItem';
 import LoungeMenuItem from './LoungeMenuItem';
 import ParkingMenuItem from './ParkingMenuItem';
-import InsuranceMenuItem from './InsuranceMenuItem';
+import InsuranceMenuItemContainer from './insuranceMenuItem/InsuranceMenuItemContainer';
 import CarRentalMenuItem from './CarRentalMenuItem';
 import TransportationMenuItem from './TransportationMenuItem';
 import type { TripServiceRefreshContainer as BookingType } from './__generated__/TripServiceRefreshContainer.graphql';
@@ -80,7 +80,10 @@ class TripServiceRefreshContainer extends React.Component<Props, State> {
       <TitledMenuGroup
         title={<Translation id="mmb.trip_services.general_services" />}
       >
-        <InsuranceMenuItem onOpenInsurance={this.openInsurance} />
+        <InsuranceMenuItemContainer
+          onOpenInsurance={this.openInsurance}
+          data={this.props.data}
+        />
       </TitledMenuGroup>
 
       <TitledMenuGroup
@@ -116,6 +119,7 @@ export default createRefetchContainer(
     fragment TripServiceRefreshContainer on BookingInterface {
       databaseId
       authToken
+      ...InsuranceMenuItemContainer
       availableWhitelabeledServices {
         ...CarRentalMenuItem
         ...LoungeMenuItem
diff --git a/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainer.graphql.js b/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainer.graphql.js
index 81c627b7..96ee59b7 100644
--- a/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainer.graphql.js
+++ b/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainer.graphql.js
@@ -10,6 +10,7 @@
 import type { ConcreteFragment } from 'relay-runtime';
 type CarRentalMenuItem$ref = any;
 type HotelMenuItem$ref = any;
+type InsuranceMenuItemContainer$ref = any;
 type LoungeMenuItem$ref = any;
 type ParkingMenuItem$ref = any;
 type TransportationMenuItem$ref = any;
@@ -21,6 +22,7 @@ export type TripServiceRefreshContainer = {|
   +availableWhitelabeledServices: ?{|
     +$fragmentRefs: CarRentalMenuItem$ref & LoungeMenuItem$ref & ParkingMenuItem$ref & HotelMenuItem$ref & TransportationMenuItem$ref
   |},
+  +$fragmentRefs: InsuranceMenuItemContainer$ref,
   +$refType: TripServiceRefreshContainer$ref,
 |};
 */
@@ -47,6 +49,11 @@ const node/*: ConcreteFragment*/ = {
       "args": null,
       "storageKey": null
     },
+    {
+      "kind": "FragmentSpread",
+      "name": "InsuranceMenuItemContainer",
+      "args": null
+    },
     {
       "kind": "LinkedField",
       "alias": null,
@@ -86,5 +93,5 @@ const node/*: ConcreteFragment*/ = {
   ]
 };
 // prettier-ignore
-(node/*: any*/).hash = '8af9547e951da88fbd1f9b4f0004b8f9';
+(node/*: any*/).hash = 'ee259798be67d3e9544405499d5be3c9';
 module.exports = node;
diff --git a/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainerQuery.graphql.js b/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainerQuery.graphql.js
index 8d16440e..2f0e935b 100644
--- a/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainerQuery.graphql.js
+++ b/app/MMB/src/scenes/tripServices/__generated__/TripServiceRefreshContainerQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 9747e80b93acc6bf17e2bd2f22f2273c
+ * @relayHash 88a6144f59c78546ae57e90415cf8926
  */
 
 /* eslint-disable */
@@ -37,6 +37,7 @@ query TripServiceRefreshContainerQuery(
 fragment TripServiceRefreshContainer on BookingInterface {
   databaseId
   authToken
+  ...InsuranceMenuItemContainer
   availableWhitelabeledServices {
     ...CarRentalMenuItem
     ...LoungeMenuItem
@@ -46,6 +47,30 @@ fragment TripServiceRefreshContainer on BookingInterface {
   }
 }
 
+fragment InsuranceMenuItemContainer on BookingInterface {
+  __typename
+  status
+  passengers {
+    nationality
+  }
+  isPastBooking
+  ... on BookingOneWay {
+    trip {
+      ...InsuranceMenuItem
+    }
+  }
+  ... on BookingReturn {
+    outbound {
+      ...InsuranceMenuItem
+    }
+  }
+  ... on BookingMulticity {
+    trips {
+      ...InsuranceMenuItem
+    }
+  }
+}
+
 fragment CarRentalMenuItem on WhitelabeledServices {
   carRental {
     relevantCities {
@@ -126,6 +151,12 @@ fragment LocationItem on HotelServiceRelevantLocation {
     id
   }
 }
+
+fragment InsuranceMenuItem on Trip {
+  departure {
+    time
+  }
+}
 */
 
 const node/*: ConcreteRequest*/ = (function(){
@@ -219,13 +250,33 @@ v5 = {
 v6 = [
   v2,
   v5
+],
+v7 = [
+  {
+    "kind": "LinkedField",
+    "alias": null,
+    "name": "departure",
+    "storageKey": null,
+    "args": null,
+    "concreteType": "RouteStop",
+    "plural": false,
+    "selections": [
+      {
+        "kind": "ScalarField",
+        "alias": null,
+        "name": "time",
+        "args": null,
+        "storageKey": null
+      }
+    ]
+  }
 ];
 return {
   "kind": "Request",
   "operationKind": "query",
   "name": "TripServiceRefreshContainerQuery",
   "id": null,
-  "text": "query TripServiceRefreshContainerQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TripServiceRefreshContainer\n    id\n  }\n}\n\nfragment TripServiceRefreshContainer on BookingInterface {\n  databaseId\n  authToken\n  availableWhitelabeledServices {\n    ...CarRentalMenuItem\n    ...LoungeMenuItem\n    ...ParkingMenuItem\n    ...HotelMenuItem\n    ...TransportationMenuItem\n  }\n}\n\nfragment CarRentalMenuItem on WhitelabeledServices {\n  carRental {\n    relevantCities {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment LoungeMenuItem on WhitelabeledServices {\n  lounge {\n    relevantAirports {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment ParkingMenuItem on WhitelabeledServices {\n  parking {\n    whitelabelURL\n  }\n}\n\nfragment HotelMenuItem on WhitelabeledServices {\n  hotel {\n    relevantLocations {\n      ...LocationItem\n      location {\n        id\n      }\n      hotelCity {\n        id\n        name\n      }\n    }\n  }\n}\n\nfragment TransportationMenuItem on WhitelabeledServices {\n  transportation {\n    relevantLocations {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n      date\n    }\n  }\n}\n\nfragment LocationPopupButton on Location {\n  city {\n    name\n  }\n  locationId\n  ...CountryFlag\n}\n\nfragment CountryFlag on Location {\n  countryFlagURL\n}\n\nfragment LocationItem on HotelServiceRelevantLocation {\n  hotelCity {\n    id\n    name\n  }\n  location {\n    ...LocationPopupButton\n    id\n  }\n}\n",
+  "text": "query TripServiceRefreshContainerQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TripServiceRefreshContainer\n    id\n  }\n}\n\nfragment TripServiceRefreshContainer on BookingInterface {\n  databaseId\n  authToken\n  ...InsuranceMenuItemContainer\n  availableWhitelabeledServices {\n    ...CarRentalMenuItem\n    ...LoungeMenuItem\n    ...ParkingMenuItem\n    ...HotelMenuItem\n    ...TransportationMenuItem\n  }\n}\n\nfragment InsuranceMenuItemContainer on BookingInterface {\n  __typename\n  status\n  passengers {\n    nationality\n  }\n  isPastBooking\n  ... on BookingOneWay {\n    trip {\n      ...InsuranceMenuItem\n    }\n  }\n  ... on BookingReturn {\n    outbound {\n      ...InsuranceMenuItem\n    }\n  }\n  ... on BookingMulticity {\n    trips {\n      ...InsuranceMenuItem\n    }\n  }\n}\n\nfragment CarRentalMenuItem on WhitelabeledServices {\n  carRental {\n    relevantCities {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment LoungeMenuItem on WhitelabeledServices {\n  lounge {\n    relevantAirports {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment ParkingMenuItem on WhitelabeledServices {\n  parking {\n    whitelabelURL\n  }\n}\n\nfragment HotelMenuItem on WhitelabeledServices {\n  hotel {\n    relevantLocations {\n      ...LocationItem\n      location {\n        id\n      }\n      hotelCity {\n        id\n        name\n      }\n    }\n  }\n}\n\nfragment TransportationMenuItem on WhitelabeledServices {\n  transportation {\n    relevantLocations {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n      date\n    }\n  }\n}\n\nfragment LocationPopupButton on Location {\n  city {\n    name\n  }\n  locationId\n  ...CountryFlag\n}\n\nfragment CountryFlag on Location {\n  countryFlagURL\n}\n\nfragment LocationItem on HotelServiceRelevantLocation {\n  hotelCity {\n    id\n    name\n  }\n  location {\n    ...LocationPopupButton\n    id\n  }\n}\n\nfragment InsuranceMenuItem on Trip {\n  departure {\n    time\n  }\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
@@ -269,7 +320,7 @@ return {
           {
             "kind": "ScalarField",
             "alias": null,
-            "name": "__typename",
+            "name": "isPastBooking",
             "args": null,
             "storageKey": null
           },
@@ -280,6 +331,38 @@ return {
             "args": null,
             "storageKey": null
           },
+          {
+            "kind": "ScalarField",
+            "alias": null,
+            "name": "__typename",
+            "args": null,
+            "storageKey": null
+          },
+          {
+            "kind": "ScalarField",
+            "alias": null,
+            "name": "status",
+            "args": null,
+            "storageKey": null
+          },
+          {
+            "kind": "LinkedField",
+            "alias": null,
+            "name": "passengers",
+            "storageKey": null,
+            "args": null,
+            "concreteType": "Passenger",
+            "plural": true,
+            "selections": [
+              {
+                "kind": "ScalarField",
+                "alias": null,
+                "name": "nationality",
+                "args": null,
+                "storageKey": null
+              }
+            ]
+          },
           {
             "kind": "ScalarField",
             "alias": null,
@@ -419,7 +502,55 @@ return {
               }
             ]
           },
-          v4
+          v4,
+          {
+            "kind": "InlineFragment",
+            "type": "BookingOneWay",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "trip",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": false,
+                "selections": v7
+              }
+            ]
+          },
+          {
+            "kind": "InlineFragment",
+            "type": "BookingMulticity",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "trips",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": true,
+                "selections": v7
+              }
+            ]
+          },
+          {
+            "kind": "InlineFragment",
+            "type": "BookingReturn",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "outbound",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": false,
+                "selections": v7
+              }
+            ]
+          }
         ]
       }
     ]
diff --git a/app/MMB/src/scenes/tripServices/__generated__/TripServicesQuery.graphql.js b/app/MMB/src/scenes/tripServices/__generated__/TripServicesQuery.graphql.js
index e9ffb535..685ce6e3 100644
--- a/app/MMB/src/scenes/tripServices/__generated__/TripServicesQuery.graphql.js
+++ b/app/MMB/src/scenes/tripServices/__generated__/TripServicesQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 9f8b79a18d02a09d42288f68a69f9d8f
+ * @relayHash 9af89937d96fad3df21f561884a337b2
  */
 
 /* eslint-disable */
@@ -37,6 +37,7 @@ query TripServicesQuery(
 fragment TripServiceRefreshContainer on BookingInterface {
   databaseId
   authToken
+  ...InsuranceMenuItemContainer
   availableWhitelabeledServices {
     ...CarRentalMenuItem
     ...LoungeMenuItem
@@ -46,6 +47,30 @@ fragment TripServiceRefreshContainer on BookingInterface {
   }
 }
 
+fragment InsuranceMenuItemContainer on BookingInterface {
+  __typename
+  status
+  passengers {
+    nationality
+  }
+  isPastBooking
+  ... on BookingOneWay {
+    trip {
+      ...InsuranceMenuItem
+    }
+  }
+  ... on BookingReturn {
+    outbound {
+      ...InsuranceMenuItem
+    }
+  }
+  ... on BookingMulticity {
+    trips {
+      ...InsuranceMenuItem
+    }
+  }
+}
+
 fragment CarRentalMenuItem on WhitelabeledServices {
   carRental {
     relevantCities {
@@ -126,6 +151,12 @@ fragment LocationItem on HotelServiceRelevantLocation {
     id
   }
 }
+
+fragment InsuranceMenuItem on Trip {
+  departure {
+    time
+  }
+}
 */
 
 const node/*: ConcreteRequest*/ = (function(){
@@ -219,13 +250,33 @@ v5 = {
 v6 = [
   v2,
   v5
+],
+v7 = [
+  {
+    "kind": "LinkedField",
+    "alias": null,
+    "name": "departure",
+    "storageKey": null,
+    "args": null,
+    "concreteType": "RouteStop",
+    "plural": false,
+    "selections": [
+      {
+        "kind": "ScalarField",
+        "alias": null,
+        "name": "time",
+        "args": null,
+        "storageKey": null
+      }
+    ]
+  }
 ];
 return {
   "kind": "Request",
   "operationKind": "query",
   "name": "TripServicesQuery",
   "id": null,
-  "text": "query TripServicesQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TripServiceRefreshContainer\n    id\n  }\n}\n\nfragment TripServiceRefreshContainer on BookingInterface {\n  databaseId\n  authToken\n  availableWhitelabeledServices {\n    ...CarRentalMenuItem\n    ...LoungeMenuItem\n    ...ParkingMenuItem\n    ...HotelMenuItem\n    ...TransportationMenuItem\n  }\n}\n\nfragment CarRentalMenuItem on WhitelabeledServices {\n  carRental {\n    relevantCities {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment LoungeMenuItem on WhitelabeledServices {\n  lounge {\n    relevantAirports {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment ParkingMenuItem on WhitelabeledServices {\n  parking {\n    whitelabelURL\n  }\n}\n\nfragment HotelMenuItem on WhitelabeledServices {\n  hotel {\n    relevantLocations {\n      ...LocationItem\n      location {\n        id\n      }\n      hotelCity {\n        id\n        name\n      }\n    }\n  }\n}\n\nfragment TransportationMenuItem on WhitelabeledServices {\n  transportation {\n    relevantLocations {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n      date\n    }\n  }\n}\n\nfragment LocationPopupButton on Location {\n  city {\n    name\n  }\n  locationId\n  ...CountryFlag\n}\n\nfragment CountryFlag on Location {\n  countryFlagURL\n}\n\nfragment LocationItem on HotelServiceRelevantLocation {\n  hotelCity {\n    id\n    name\n  }\n  location {\n    ...LocationPopupButton\n    id\n  }\n}\n",
+  "text": "query TripServicesQuery(\n  $bookingId: Int!\n  $authToken: String!\n) {\n  singleBooking(id: $bookingId, authToken: $authToken) {\n    __typename\n    ...TripServiceRefreshContainer\n    id\n  }\n}\n\nfragment TripServiceRefreshContainer on BookingInterface {\n  databaseId\n  authToken\n  ...InsuranceMenuItemContainer\n  availableWhitelabeledServices {\n    ...CarRentalMenuItem\n    ...LoungeMenuItem\n    ...ParkingMenuItem\n    ...HotelMenuItem\n    ...TransportationMenuItem\n  }\n}\n\nfragment InsuranceMenuItemContainer on BookingInterface {\n  __typename\n  status\n  passengers {\n    nationality\n  }\n  isPastBooking\n  ... on BookingOneWay {\n    trip {\n      ...InsuranceMenuItem\n    }\n  }\n  ... on BookingReturn {\n    outbound {\n      ...InsuranceMenuItem\n    }\n  }\n  ... on BookingMulticity {\n    trips {\n      ...InsuranceMenuItem\n    }\n  }\n}\n\nfragment CarRentalMenuItem on WhitelabeledServices {\n  carRental {\n    relevantCities {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment LoungeMenuItem on WhitelabeledServices {\n  lounge {\n    relevantAirports {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n    }\n  }\n}\n\nfragment ParkingMenuItem on WhitelabeledServices {\n  parking {\n    whitelabelURL\n  }\n}\n\nfragment HotelMenuItem on WhitelabeledServices {\n  hotel {\n    relevantLocations {\n      ...LocationItem\n      location {\n        id\n      }\n      hotelCity {\n        id\n        name\n      }\n    }\n  }\n}\n\nfragment TransportationMenuItem on WhitelabeledServices {\n  transportation {\n    relevantLocations {\n      whitelabelURL\n      location {\n        ...LocationPopupButton\n        id\n      }\n      date\n    }\n  }\n}\n\nfragment LocationPopupButton on Location {\n  city {\n    name\n  }\n  locationId\n  ...CountryFlag\n}\n\nfragment CountryFlag on Location {\n  countryFlagURL\n}\n\nfragment LocationItem on HotelServiceRelevantLocation {\n  hotelCity {\n    id\n    name\n  }\n  location {\n    ...LocationPopupButton\n    id\n  }\n}\n\nfragment InsuranceMenuItem on Trip {\n  departure {\n    time\n  }\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
@@ -269,7 +320,7 @@ return {
           {
             "kind": "ScalarField",
             "alias": null,
-            "name": "__typename",
+            "name": "isPastBooking",
             "args": null,
             "storageKey": null
           },
@@ -280,6 +331,38 @@ return {
             "args": null,
             "storageKey": null
           },
+          {
+            "kind": "ScalarField",
+            "alias": null,
+            "name": "__typename",
+            "args": null,
+            "storageKey": null
+          },
+          {
+            "kind": "ScalarField",
+            "alias": null,
+            "name": "status",
+            "args": null,
+            "storageKey": null
+          },
+          {
+            "kind": "LinkedField",
+            "alias": null,
+            "name": "passengers",
+            "storageKey": null,
+            "args": null,
+            "concreteType": "Passenger",
+            "plural": true,
+            "selections": [
+              {
+                "kind": "ScalarField",
+                "alias": null,
+                "name": "nationality",
+                "args": null,
+                "storageKey": null
+              }
+            ]
+          },
           {
             "kind": "ScalarField",
             "alias": null,
@@ -419,7 +502,55 @@ return {
               }
             ]
           },
-          v4
+          v4,
+          {
+            "kind": "InlineFragment",
+            "type": "BookingOneWay",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "trip",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": false,
+                "selections": v7
+              }
+            ]
+          },
+          {
+            "kind": "InlineFragment",
+            "type": "BookingMulticity",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "trips",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": true,
+                "selections": v7
+              }
+            ]
+          },
+          {
+            "kind": "InlineFragment",
+            "type": "BookingReturn",
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "outbound",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Trip",
+                "plural": false,
+                "selections": v7
+              }
+            ]
+          }
         ]
       }
     ]
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItem.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItem.js
new file mode 100644
index 00000000..6f70ef5f
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItem.js
@@ -0,0 +1,58 @@
+// @flow strict
+
+import * as React from 'react';
+import idx from 'idx';
+import { TextIcon } from '@kiwicom/mobile-shared';
+import { Translation, DateUtils, Alert } from '@kiwicom/mobile-localization';
+import { TodoMenuItem } from '@kiwicom/mobile-navigation';
+import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
+
+import type { InsuranceMenuItem as InsuranceMenuItemType } from './__generated__/InsuranceMenuItem.graphql';
+
+type Props = {|
+  +onOpenInsurance: () => void,
+  +data: InsuranceMenuItemType,
+|};
+
+export class InsuranceMenuItem extends React.Component<Props> {
+  isMoreThan48HoursBefore = () => {
+    const departureTime = idx(this.props.data, _ => _.departure.time);
+    return (
+      departureTime &&
+      DateUtils.diffInHours(new Date(departureTime), DateUtils.getUTCNow()) > 48
+    );
+  };
+
+  onPress = () => {
+    if (this.isMoreThan48HoursBefore()) {
+      this.props.onOpenInsurance();
+    } else {
+      Alert.translatedAlert(null, {
+        id: 'mmb.trip_services.insurance.no_changes',
+      });
+    }
+  };
+
+  render = () => {
+    return (
+      <TodoMenuItem
+        title={
+          <Translation id="mmb.trip_services.general_services.insurance" />
+        }
+        icon={<TextIcon code="'" />}
+        onPress={this.onPress}
+      />
+    );
+  };
+}
+
+export default createFragmentContainer(
+  InsuranceMenuItem,
+  graphql`
+    fragment InsuranceMenuItem on Trip {
+      departure {
+        time
+      }
+    }
+  `,
+);
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItemContainer.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItemContainer.js
new file mode 100644
index 00000000..f025719a
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/InsuranceMenuItemContainer.js
@@ -0,0 +1,87 @@
+// @flow strict
+
+import * as React from 'react';
+import idx from 'idx';
+import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
+
+import type { InsuranceMenuItemContainer as InsuranceMenuItemContainerType } from './__generated__/InsuranceMenuItemContainer.graphql';
+import InsuranceMenuItem from './InsuranceMenuItem';
+
+type Props = {|
+  +onOpenInsurance: () => void,
+  +data: InsuranceMenuItemContainerType,
+|};
+
+export class InsuranceMenuItemContainer extends React.Component<Props> {
+  isPastBooking = () => idx(this.props.data, _ => _.isPastBooking);
+  isStatusConfirmed = () => idx(this.props.data, _ => _.status) === 'CONFIRMED';
+
+  noUSPassengers = () => {
+    const passengers = idx(this.props.data, _ => _.passengers);
+    return (
+      passengers != null &&
+      passengers.every(passenger => {
+        const nationality = passenger && passenger.nationality;
+        return nationality != null && nationality.toLowerCase() !== 'us';
+      })
+    );
+  };
+
+  displayMenuItem = () =>
+    !this.isPastBooking() && this.isStatusConfirmed() && this.noUSPassengers();
+
+  getData = () => {
+    switch (this.props.data.__typename) {
+      case 'BookingOneWay':
+        return idx(this.props.data, _ => _.trip);
+      case 'BookingReturn':
+        return idx(this.props.data, _ => _.outbound);
+      case 'BookingMulticity':
+        return idx(this.props.data, _ => _.trips[0]);
+      default:
+        return null;
+    }
+  };
+
+  render = () => {
+    if (!this.displayMenuItem()) {
+      return null;
+    }
+
+    return (
+      <InsuranceMenuItem
+        onOpenInsurance={this.props.onOpenInsurance}
+        data={this.getData()}
+      />
+    );
+  };
+}
+
+export default createFragmentContainer(
+  InsuranceMenuItemContainer,
+  graphql`
+    fragment InsuranceMenuItemContainer on BookingInterface {
+      __typename
+      status
+      passengers {
+        nationality
+      }
+      isPastBooking
+      ... on BookingOneWay {
+        trip {
+          ...InsuranceMenuItem
+        }
+      }
+      ... on BookingReturn {
+        outbound {
+          ...InsuranceMenuItem
+        }
+      }
+      ... on BookingMulticity {
+        trips {
+          ...InsuranceMenuItem
+        }
+      }
+    }
+  `,
+);
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItem.graphql.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItem.graphql.js
new file mode 100644
index 00000000..07ba8cbd
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItem.graphql.js
@@ -0,0 +1,51 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type InsuranceMenuItem$ref: FragmentReference;
+export type InsuranceMenuItem = {|
+  +departure: ?{|
+    +time: ?any
+  |},
+  +$refType: InsuranceMenuItem$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "InsuranceMenuItem",
+  "type": "Trip",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "departure",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "RouteStop",
+      "plural": false,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "time",
+          "args": null,
+          "storageKey": null
+        }
+      ]
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = '80555317a7b3c37f53afb737f821ac34';
+module.exports = node;
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItemContainer.graphql.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItemContainer.graphql.js
new file mode 100644
index 00000000..2e680a3e
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__generated__/InsuranceMenuItemContainer.graphql.js
@@ -0,0 +1,143 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+type InsuranceMenuItem$ref = any;
+export type BookingStatus = "CANCELLED" | "CLOSED" | "CONFIRMED" | "DELETED" | "EXPIRED" | "NEW" | "PENDING" | "REFUNDED" | "%future added value";
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type InsuranceMenuItemContainer$ref: FragmentReference;
+export type InsuranceMenuItemContainer = {|
+  +__typename: string,
+  +status: ?BookingStatus,
+  +passengers: ?$ReadOnlyArray<?{|
+    +nationality: ?string
+  |}>,
+  +isPastBooking: ?boolean,
+  +trip?: ?{|
+    +$fragmentRefs: InsuranceMenuItem$ref
+  |},
+  +outbound?: ?{|
+    +$fragmentRefs: InsuranceMenuItem$ref
+  |},
+  +trips?: ?$ReadOnlyArray<?{|
+    +$fragmentRefs: InsuranceMenuItem$ref
+  |}>,
+  +$refType: InsuranceMenuItemContainer$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = (function(){
+var v0 = [
+  {
+    "kind": "FragmentSpread",
+    "name": "InsuranceMenuItem",
+    "args": null
+  }
+];
+return {
+  "kind": "Fragment",
+  "name": "InsuranceMenuItemContainer",
+  "type": "BookingInterface",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "__typename",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "status",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "passengers",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Passenger",
+      "plural": true,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "nationality",
+          "args": null,
+          "storageKey": null
+        }
+      ]
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "isPastBooking",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "InlineFragment",
+      "type": "BookingMulticity",
+      "selections": [
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "trips",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Trip",
+          "plural": true,
+          "selections": v0
+        }
+      ]
+    },
+    {
+      "kind": "InlineFragment",
+      "type": "BookingReturn",
+      "selections": [
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "outbound",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Trip",
+          "plural": false,
+          "selections": v0
+        }
+      ]
+    },
+    {
+      "kind": "InlineFragment",
+      "type": "BookingOneWay",
+      "selections": [
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "trip",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Trip",
+          "plural": false,
+          "selections": v0
+        }
+      ]
+    }
+  ]
+};
+})();
+// prettier-ignore
+(node/*: any*/).hash = 'c9116e5f9baa3b77ce476c5694e461a9';
+module.exports = node;
diff --git a/packages/localization/src/vocabularies/ManageMyBooking.js b/packages/localization/src/vocabularies/ManageMyBooking.js
index 1484df26..a38d97ca 100644
--- a/packages/localization/src/vocabularies/ManageMyBooking.js
+++ b/packages/localization/src/vocabularies/ManageMyBooking.js
@@ -125,6 +125,8 @@ export default {
   'mmb.trip_services.order.process_to_refund': 'Proceed With The Refund',
 
   // MMB Insurance
+  'mmb.trip_services.insurance.no_changes':
+    'Insurance cannot be changed less than 48 hours before your trip.',
   'mmb.trip_services.insurance.variant.none': 'No Insurance',
   'mmb.trip_services.insurance.variant.basic': 'Travel Basic',
   'mmb.trip_services.insurance.variant.plus': 'Travel Plus',


Test patch:
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItem.test.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItem.test.js
new file mode 100644
index 00000000..530a2995
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItem.test.js
@@ -0,0 +1,70 @@
+// @flow
+
+import { Alert } from '@kiwicom/mobile-localization';
+import MockDate from 'mockdate';
+
+import { InsuranceMenuItem } from '../InsuranceMenuItem';
+
+describe('InsuranceMenuItem', () => {
+  let spy;
+  beforeEach(() => {
+    MockDate.set('2016-12-21T23:36:07.071Z');
+    spy = jest.spyOn(Alert, 'translatedAlert');
+  });
+
+  afterEach(() => {
+    spy.mockRestore();
+    MockDate.reset();
+  });
+
+  function noop() {}
+
+  it('shows alert if 48 hours before first departure', () => {
+    const data = {
+      departure: {
+        time: '2016-12-22T23:36:07.071Z',
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItem = new InsuranceMenuItem({
+      data,
+      onOpenInsurance: noop,
+    });
+
+    const spyOpenInsurance = jest.spyOn(
+      insuranceMenuItem.props,
+      'onOpenInsurance',
+    );
+    expect(insuranceMenuItem.isMoreThan48HoursBefore()).toBe(false);
+    insuranceMenuItem.onPress();
+    expect(spy).toHaveBeenCalled();
+    expect(spyOpenInsurance).not.toHaveBeenCalled();
+    spyOpenInsurance.mockRestore();
+  });
+
+  it('does not show alert if at least 48 hours before first departure', () => {
+    const data = {
+      departure: {
+        time: '2016-12-24T23:36:07.071Z',
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItem = new InsuranceMenuItem({
+      data,
+      onOpenInsurance: noop,
+    });
+
+    const spyOpenInsurance = jest.spyOn(
+      insuranceMenuItem.props,
+      'onOpenInsurance',
+    );
+
+    expect(insuranceMenuItem.isMoreThan48HoursBefore()).toBe(true);
+    insuranceMenuItem.onPress();
+    expect(spy).not.toHaveBeenCalled();
+    expect(spyOpenInsurance).toHaveBeenCalled();
+    spyOpenInsurance.mockRestore();
+  });
+});
diff --git a/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItemContainer.test.js b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItemContainer.test.js
new file mode 100644
index 00000000..d49a0ef5
--- /dev/null
+++ b/app/MMB/src/scenes/tripServices/insuranceMenuItem/__tests__/InsuranceMenuItemContainer.test.js
@@ -0,0 +1,225 @@
+// @flow
+
+import { InsuranceMenuItemContainer } from '../InsuranceMenuItemContainer';
+
+describe('InsuranceMenuItem', () => {
+  function noop() {}
+
+  it('should display if it is not a past booking, its status is confirmed, and no passengers are US citizens', async () => {
+    const data = {
+      __typename: 'BookingOneWay',
+      isPastBooking: false,
+      status: 'CONFIRMED',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trip: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenu = new InsuranceMenuItemContainer({
+      data: data,
+      onOpenInsurance: noop,
+    });
+    expect(insuranceMenu.displayMenuItem()).toBe(true);
+  });
+
+  it('should not display if it is a past booking', () => {
+    const dataPastBooking = {
+      __typename: 'BookingOneWay',
+      isPastBooking: true,
+      status: 'CONFIRMED',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trip: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItemPastBooking = new InsuranceMenuItemContainer({
+      data: dataPastBooking,
+      onOpenInsurance: noop,
+    });
+    expect(insuranceMenuItemPastBooking.displayMenuItem()).toBe(false);
+  });
+
+  it('should not display if the booking status is not confirmed', () => {
+    const data = {
+      __typename: 'BookingOneWay',
+      isPastBooking: false,
+      status: 'PENDING',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trip: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItem = new InsuranceMenuItemContainer({
+      data: data,
+      onOpenInsurance: noop,
+    });
+    expect(insuranceMenuItem.displayMenuItem()).toBe(false);
+  });
+
+  it('should not display if at least one passenger is a US citizen', () => {
+    const data = {
+      __typename: 'BookingOneWay',
+      isPastBooking: false,
+      status: 'PENDING',
+      passengers: [
+        {
+          nationality: 'US',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trip: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItem = new InsuranceMenuItemContainer({
+      data: data,
+      onOpenInsurance: noop,
+    });
+    expect(insuranceMenuItem.displayMenuItem()).toBe(false);
+  });
+
+  it('should get proper time depending on booking type', async () => {
+    const dataMulticity = {
+      __typename: 'BookingMulticity',
+      isPastBooking: false,
+      status: 'CONFIRMED',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trips: [
+        {
+          departure: {
+            time: '2016-12-24T23:36:07.071Z',
+          },
+        },
+        {
+          departure: {
+            time: '2016-12-25T23:36:07.071Z',
+          },
+        },
+        {
+          departure: {
+            time: '2016-12-26T23:36:07.071Z',
+          },
+        },
+      ],
+    };
+
+    const dataReturn = {
+      __typename: 'BookingReturn',
+      isPastBooking: false,
+      status: 'CONFIRMED',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      outbound: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+
+    const dataOneWay = {
+      __typename: 'BookingOneWay',
+      isPastBooking: false,
+      status: 'CONFIRMED',
+      passengers: [
+        {
+          nationality: 'cz',
+        },
+        {
+          nationality: 'cz',
+        },
+      ],
+      trip: {
+        departure: {
+          time: '2016-12-24T23:36:07.071Z',
+        },
+      },
+    };
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItemMulticity = new InsuranceMenuItemContainer({
+      data: dataMulticity,
+      onOpenInsurance: noop,
+    });
+
+    expect(insuranceMenuItemMulticity.getData()).toEqual({
+      departure: {
+        time: '2016-12-24T23:36:07.071Z',
+      },
+    });
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItemReturn = new InsuranceMenuItemContainer({
+      data: dataReturn,
+      onOpenInsurance: noop,
+    });
+
+    expect(insuranceMenuItemReturn.getData()).toEqual({
+      departure: {
+        time: '2016-12-24T23:36:07.071Z',
+      },
+    });
+
+    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
+    const insuranceMenuItemOneWay = new InsuranceMenuItemContainer({
+      data: dataOneWay,
+      onOpenInsurance: noop,
+    });
+
+    expect(insuranceMenuItemOneWay.getData()).toEqual({
+      departure: {
+        time: '2016-12-24T23:36:07.071Z',
+      },
+    });
+  });
+});