Repository: kiwicom/mobile
Pull request #680 (2018-05-30 12:11:29)

iOS navigation connection with real app

tbergq: Don't really know what is going on here, So I will wait for review from @grabbou also before I merge

Patch:
diff --git a/.gitattributes b/.gitattributes
index 928f0629..5a5cec23 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
 *.pbxproj -text
+*.graphql.js linguist-generated
 app/translations/screenshots/*.jpg filter=lfs diff=lfs merge=lfs -text
diff --git a/app/MMB/index.js b/app/MMB/index.js
index 4f414642..c0f37e9f 100644
--- a/app/MMB/index.js
+++ b/app/MMB/index.js
@@ -6,6 +6,7 @@ import { AuthContext } from '@kiwicom/mobile-relay';
 import { AdaptableLayout } from '@kiwicom/mobile-shared';
 
 import NavigationStack from './src/navigation/NavigationStack';
+import BookingDetailContext from './src/context/BookingDetailContext';
 
 type Props = {|
   currency: string,
@@ -16,7 +17,9 @@ class ManageMyBookingPackage extends React.Component<Props> {
   render = () => (
     <AdaptableLayout.Provider>
       <AuthContext.Provider accessToken={this.props.accessToken}>
-        <NavigationStack />
+        <BookingDetailContext.Provider>
+          <NavigationStack />
+        </BookingDetailContext.Provider>
       </AuthContext.Provider>
     </AdaptableLayout.Provider>
   );
diff --git a/app/MMB/src/MainMenu.js b/app/MMB/src/MainMenu.js
index cb4a1638..6bc7c741 100644
--- a/app/MMB/src/MainMenu.js
+++ b/app/MMB/src/MainMenu.js
@@ -2,24 +2,24 @@
 
 import * as React from 'react';
 import { ScrollView } from 'react-native';
-import { graphql, PrivateApiRenderer } from '@kiwicom/mobile-relay';
+import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
 
 import ServicesMenuGroup from './menuGroups/ServicesMenuGroup';
 import ManageMenuGroup from './menuGroups/ManageMenuGroup';
 import Header from './components/header/Header';
-import PassengerMenuGroup from './menuGroups/PassengerMenuGroup';
-import BookingDetailContext from './context/BookingDetailContext';
-import type { MainMenuQueryResponse } from './__generated__/MainMenuQuery.graphql';
+import PassengerMenuGroup from './menuGroups/passengerMenuGroup/PassengerMenuGroup';
+import type { MainMenu as BookingType } from './__generated__/MainMenu.graphql';
 
 type Props = {|
-  openMenu: string => void,
+  +openMenu: string => void,
+  +data: BookingType,
 |};
 
 type State = {|
   activeId: string,
 |};
 
-export default class MainMenu extends React.Component<Props, State> {
+class MainMenu extends React.Component<Props, State> {
   state = {
     activeId: 'mmb.main_menu.passengers.passenger_details',
   };
@@ -33,15 +33,16 @@ export default class MainMenu extends React.Component<Props, State> {
     );
   };
 
-  renderInnerComponent = (renderProps: MainMenuQueryResponse) => {
+  render = () => {
     const { activeId } = this.state;
 
     return (
       <ScrollView>
-        <Header data={renderProps.booking} />
+        <Header data={this.props.data} />
         <PassengerMenuGroup
           activeId={activeId}
           openSubmenu={this.handleOpenSubmenu}
+          data={this.props.data}
         />
         <ServicesMenuGroup
           activeId={activeId}
@@ -54,24 +55,14 @@ export default class MainMenu extends React.Component<Props, State> {
       </ScrollView>
     );
   };
-
-  render = () => (
-    <BookingDetailContext.Consumer>
-      {({ bookingId }) => (
-        <PrivateApiRenderer
-          render={this.renderInnerComponent}
-          query={graphql`
-            query MainMenuQuery($bookingId: ID!) {
-              booking(id: $bookingId) {
-                ...Header
-              }
-            }
-          `}
-          variables={{
-            bookingId: bookingId,
-          }}
-        />
-      )}
-    </BookingDetailContext.Consumer>
-  );
 }
+
+export default createFragmentContainer(
+  MainMenu,
+  graphql`
+    fragment MainMenu on Booking {
+      ...Header
+      ...PassengerMenuGroup
+    }
+  `,
+);
diff --git a/app/MMB/src/MainMenuContainer.js b/app/MMB/src/MainMenuContainer.js
new file mode 100644
index 00000000..eb49032a
--- /dev/null
+++ b/app/MMB/src/MainMenuContainer.js
@@ -0,0 +1,38 @@
+// @flow
+
+import * as React from 'react';
+import { graphql, PrivateApiRenderer } from '@kiwicom/mobile-relay';
+
+import MainMenu from './MainMenu';
+import BookingDetailContext from './context/BookingDetailContext';
+import type { MainMenuContainerQuery } from './__generated__/MainMenuContainerQuery.graphql';
+
+type Props = {|
+  +openMenu: string => void,
+|};
+
+export default class MainMenuContainer extends React.Component<Props> {
+  renderInnerComponent = (renderProps: MainMenuContainerQuery) => (
+    <MainMenu data={renderProps.booking} openMenu={this.props.openMenu} />
+  );
+
+  render = () => (
+    <BookingDetailContext.Consumer>
+      {({ bookingId }) => (
+        <PrivateApiRenderer
+          render={this.renderInnerComponent}
+          query={graphql`
+            query MainMenuContainerQuery($bookingId: ID!) {
+              booking(id: $bookingId) {
+                ...MainMenu
+              }
+            }
+          `}
+          variables={{
+            bookingId: bookingId,
+          }}
+        />
+      )}
+    </BookingDetailContext.Consumer>
+  );
+}
diff --git a/app/MMB/src/__generated__/MainMenu.graphql.js b/app/MMB/src/__generated__/MainMenu.graphql.js
new file mode 100644
index 00000000..633a9c7f
--- /dev/null
+++ b/app/MMB/src/__generated__/MainMenu.graphql.js
@@ -0,0 +1,43 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+type Header$ref = any;
+type PassengerMenuGroup$ref = any;
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type MainMenu$ref: FragmentReference;
+export type MainMenu = {|
+  +$fragmentRefs: Header$ref & PassengerMenuGroup$ref,
+  +$refType: MainMenu$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "MainMenu",
+  "type": "Booking",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "FragmentSpread",
+      "name": "Header",
+      "args": null
+    },
+    {
+      "kind": "FragmentSpread",
+      "name": "PassengerMenuGroup",
+      "args": null
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = 'b9f1dc28e3edbee53bece271a8361276';
+module.exports = node;
diff --git a/app/MMB/src/__generated__/MainMenuQuery.graphql.js b/app/MMB/src/__generated__/MainMenuContainerQuery.graphql.js
similarity index 59%
rename from app/MMB/src/__generated__/MainMenuQuery.graphql.js
rename to app/MMB/src/__generated__/MainMenuContainerQuery.graphql.js
index a1b23d42..9c2d9fd8 100644
--- a/app/MMB/src/__generated__/MainMenuQuery.graphql.js
+++ b/app/MMB/src/__generated__/MainMenuContainerQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 85dcbc89a490cc0ddb8da8e75af09a7b
+ * @relayHash c406a37c021620f80ab6b9da12848ec4
  */
 
 /* eslint-disable */
@@ -9,28 +9,33 @@
 
 /*::
 import type { ConcreteRequest } from 'relay-runtime';
-type Header$ref = any;
-export type MainMenuQueryVariables = {|
+type MainMenu$ref = any;
+export type MainMenuContainerQueryVariables = {|
   bookingId: string
 |};
-export type MainMenuQueryResponse = {|
+export type MainMenuContainerQueryResponse = {|
   +booking: ?{|
-    +$fragmentRefs: Header$ref
+    +$fragmentRefs: MainMenu$ref
   |}
 |};
 */
 
 
 /*
-query MainMenuQuery(
+query MainMenuContainerQuery(
   $bookingId: ID!
 ) {
   booking(id: $bookingId) {
-    ...Header
+    ...MainMenu
     id
   }
 }
 
+fragment MainMenu on Booking {
+  ...Header
+  ...PassengerMenuGroup
+}
+
 fragment Header on Booking {
   isPastBooking
   ...StatusBar
@@ -38,6 +43,37 @@ fragment Header on Booking {
   ...HeaderImage
 }
 
+fragment PassengerMenuGroup on Booking {
+  ...PassengerMenuDetail
+}
+
+fragment PassengerMenuDetail on Booking {
+  ...Visa
+  passengers {
+    databaseId
+    ...Passenger
+  }
+}
+
+fragment Visa on Booking {
+  passengers {
+    visaInformation {
+      requiredIn {
+        name
+      }
+      warningIn {
+        name
+      }
+    }
+  }
+}
+
+fragment Passenger on Passenger {
+  fullName
+  title
+  birthday
+}
+
 fragment StatusBar on Booking {
   ...StatusBarIcon
   databaseId
@@ -149,11 +185,27 @@ v1 = [
 v2 = {
   "kind": "ScalarField",
   "alias": null,
-  "name": "localTime",
+  "name": "databaseId",
   "args": null,
   "storageKey": null
 },
 v3 = [
+  {
+    "kind": "ScalarField",
+    "alias": null,
+    "name": "name",
+    "args": null,
+    "storageKey": null
+  }
+],
+v4 = {
+  "kind": "ScalarField",
+  "alias": null,
+  "name": "localTime",
+  "args": null,
+  "storageKey": null
+},
+v5 = [
   {
     "kind": "LinkedField",
     "alias": null,
@@ -171,15 +223,7 @@ v3 = [
         "args": null,
         "concreteType": "LocationArea",
         "plural": false,
-        "selections": [
-          {
-            "kind": "ScalarField",
-            "alias": null,
-            "name": "name",
-            "args": null,
-            "storageKey": null
-          }
-        ]
+        "selections": v3
       },
       {
         "kind": "ScalarField",
@@ -190,16 +234,16 @@ v3 = [
       }
     ]
   },
-  v2
+  v4
 ],
-v4 = {
+v6 = {
   "kind": "ScalarField",
   "alias": null,
   "name": "duration",
   "args": null,
   "storageKey": null
 },
-v5 = [
+v7 = [
   {
     "kind": "LinkedField",
     "alias": null,
@@ -208,7 +252,7 @@ v5 = [
     "args": null,
     "concreteType": "RouteStop",
     "plural": false,
-    "selections": v3
+    "selections": v5
   },
   {
     "kind": "LinkedField",
@@ -218,30 +262,30 @@ v5 = [
     "args": null,
     "concreteType": "RouteStop",
     "plural": false,
-    "selections": v3
+    "selections": v5
   },
-  v4
+  v6
 ],
-v6 = {
+v8 = {
   "kind": "ScalarField",
   "alias": null,
   "name": "id",
   "args": null,
   "storageKey": null
 },
-v7 = [
-  v2
+v9 = [
+  v4
 ];
 return {
   "kind": "Request",
   "operationKind": "query",
-  "name": "MainMenuQuery",
+  "name": "MainMenuContainerQuery",
   "id": null,
-  "text": "query MainMenuQuery(\n  $bookingId: ID!\n) {\n  booking(id: $bookingId) {\n    ...Header\n    id\n  }\n}\n\nfragment Header on Booking {\n  isPastBooking\n  ...StatusBar\n  ...TripInfo\n  ...HeaderImage\n}\n\nfragment StatusBar on Booking {\n  ...StatusBarIcon\n  databaseId\n}\n\nfragment TripInfo on Booking {\n  type\n  oneWay {\n    ...TripInfoOneWay\n    id\n  }\n  return {\n    ...TripInfoReturn\n    id\n  }\n  multicity {\n    ...TripInfoMulticity\n    id\n  }\n}\n\nfragment HeaderImage on Booking {\n  destinationImageUrl(dimensions: _375x165)\n}\n\nfragment TripInfoOneWay on BookingOneWay {\n  trip {\n    ...TripCities\n    ...TripTimes\n  }\n}\n\nfragment TripInfoReturn on BookingReturn {\n  outbound {\n    ...TripCities\n    ...TripTimes\n  }\n  inbound {\n    ...TripTimes\n  }\n}\n\nfragment TripInfoMulticity on BookingMulticity {\n  trips {\n    ...TripCities\n    ...TripTimes\n  }\n}\n\nfragment TripCities on Trip {\n  departure {\n    ...Location\n  }\n  arrival {\n    ...Location\n  }\n}\n\nfragment TripTimes on Trip {\n  ...Duration\n  departure {\n    ...DateTime\n  }\n  arrival {\n    ...DateTime\n  }\n}\n\nfragment Duration on Trip {\n  duration\n}\n\nfragment DateTime on RouteStop {\n  localTime\n}\n\nfragment Location on RouteStop {\n  airport {\n    city {\n      name\n    }\n    countryFlagURL\n  }\n}\n\nfragment StatusBarIcon on Booking {\n  status\n  isPastBooking\n}\n",
+  "text": "query MainMenuContainerQuery(\n  $bookingId: ID!\n) {\n  booking(id: $bookingId) {\n    ...MainMenu\n    id\n  }\n}\n\nfragment MainMenu on Booking {\n  ...Header\n  ...PassengerMenuGroup\n}\n\nfragment Header on Booking {\n  isPastBooking\n  ...StatusBar\n  ...TripInfo\n  ...HeaderImage\n}\n\nfragment PassengerMenuGroup on Booking {\n  ...PassengerMenuDetail\n}\n\nfragment PassengerMenuDetail on Booking {\n  ...Visa\n  passengers {\n    databaseId\n    ...Passenger\n  }\n}\n\nfragment Visa on Booking {\n  passengers {\n    visaInformation {\n      requiredIn {\n        name\n      }\n      warningIn {\n        name\n      }\n    }\n  }\n}\n\nfragment Passenger on Passenger {\n  fullName\n  title\n  birthday\n}\n\nfragment StatusBar on Booking {\n  ...StatusBarIcon\n  databaseId\n}\n\nfragment TripInfo on Booking {\n  type\n  oneWay {\n    ...TripInfoOneWay\n    id\n  }\n  return {\n    ...TripInfoReturn\n    id\n  }\n  multicity {\n    ...TripInfoMulticity\n    id\n  }\n}\n\nfragment HeaderImage on Booking {\n  destinationImageUrl(dimensions: _375x165)\n}\n\nfragment TripInfoOneWay on BookingOneWay {\n  trip {\n    ...TripCities\n    ...TripTimes\n  }\n}\n\nfragment TripInfoReturn on BookingReturn {\n  outbound {\n    ...TripCities\n    ...TripTimes\n  }\n  inbound {\n    ...TripTimes\n  }\n}\n\nfragment TripInfoMulticity on BookingMulticity {\n  trips {\n    ...TripCities\n    ...TripTimes\n  }\n}\n\nfragment TripCities on Trip {\n  departure {\n    ...Location\n  }\n  arrival {\n    ...Location\n  }\n}\n\nfragment TripTimes on Trip {\n  ...Duration\n  departure {\n    ...DateTime\n  }\n  arrival {\n    ...DateTime\n  }\n}\n\nfragment Duration on Trip {\n  duration\n}\n\nfragment DateTime on RouteStop {\n  localTime\n}\n\nfragment Location on RouteStop {\n  airport {\n    city {\n      name\n    }\n    countryFlagURL\n  }\n}\n\nfragment StatusBarIcon on Booking {\n  status\n  isPastBooking\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
-    "name": "MainMenuQuery",
+    "name": "MainMenuContainerQuery",
     "type": "RootQuery",
     "metadata": null,
     "argumentDefinitions": v0,
@@ -257,7 +301,7 @@ return {
         "selections": [
           {
             "kind": "FragmentSpread",
-            "name": "Header",
+            "name": "MainMenu",
             "args": null
           }
         ]
@@ -266,7 +310,7 @@ return {
   },
   "operation": {
     "kind": "Operation",
-    "name": "MainMenuQuery",
+    "name": "MainMenuContainerQuery",
     "argumentDefinitions": v0,
     "selections": [
       {
@@ -292,13 +336,7 @@ return {
             "args": null,
             "storageKey": null
           },
-          {
-            "kind": "ScalarField",
-            "alias": null,
-            "name": "databaseId",
-            "args": null,
-            "storageKey": null
-          },
+          v2,
           {
             "kind": "ScalarField",
             "alias": null,
@@ -323,9 +361,9 @@ return {
                 "args": null,
                 "concreteType": "Trip",
                 "plural": false,
-                "selections": v5
+                "selections": v7
               },
-              v6
+              v8
             ]
           },
           {
@@ -345,7 +383,7 @@ return {
                 "args": null,
                 "concreteType": "Trip",
                 "plural": false,
-                "selections": v5
+                "selections": v7
               },
               {
                 "kind": "LinkedField",
@@ -356,7 +394,7 @@ return {
                 "concreteType": "Trip",
                 "plural": false,
                 "selections": [
-                  v4,
+                  v6,
                   {
                     "kind": "LinkedField",
                     "alias": null,
@@ -365,7 +403,7 @@ return {
                     "args": null,
                     "concreteType": "RouteStop",
                     "plural": false,
-                    "selections": v7
+                    "selections": v9
                   },
                   {
                     "kind": "LinkedField",
@@ -375,11 +413,11 @@ return {
                     "args": null,
                     "concreteType": "RouteStop",
                     "plural": false,
-                    "selections": v7
+                    "selections": v9
                   }
                 ]
               },
-              v6
+              v8
             ]
           },
           {
@@ -399,9 +437,9 @@ return {
                 "args": null,
                 "concreteType": "Trip",
                 "plural": true,
-                "selections": v5
+                "selections": v7
               },
-              v6
+              v8
             ]
           },
           {
@@ -418,7 +456,71 @@ return {
             ],
             "storageKey": "destinationImageUrl(dimensions:\"_375x165\")"
           },
-          v6
+          {
+            "kind": "LinkedField",
+            "alias": null,
+            "name": "passengers",
+            "storageKey": null,
+            "args": null,
+            "concreteType": "Passenger",
+            "plural": true,
+            "selections": [
+              {
+                "kind": "LinkedField",
+                "alias": null,
+                "name": "visaInformation",
+                "storageKey": null,
+                "args": null,
+                "concreteType": "Visa",
+                "plural": false,
+                "selections": [
+                  {
+                    "kind": "LinkedField",
+                    "alias": null,
+                    "name": "requiredIn",
+                    "storageKey": null,
+                    "args": null,
+                    "concreteType": "Location",
+                    "plural": true,
+                    "selections": v3
+                  },
+                  {
+                    "kind": "LinkedField",
+                    "alias": null,
+                    "name": "warningIn",
+                    "storageKey": null,
+                    "args": null,
+                    "concreteType": "Location",
+                    "plural": true,
+                    "selections": v3
+                  }
+                ]
+              },
+              v2,
+              {
+                "kind": "ScalarField",
+                "alias": null,
+                "name": "fullName",
+                "args": null,
+                "storageKey": null
+              },
+              {
+                "kind": "ScalarField",
+                "alias": null,
+                "name": "title",
+                "args": null,
+                "storageKey": null
+              },
+              {
+                "kind": "ScalarField",
+                "alias": null,
+                "name": "birthday",
+                "args": null,
+                "storageKey": null
+              }
+            ]
+          },
+          v8
         ]
       }
     ]
@@ -426,5 +528,5 @@ return {
 };
 })();
 // prettier-ignore
-(node/*: any*/).hash = 'a6adfc82add8836a63278fa8e50c8c8c';
+(node/*: any*/).hash = 'b206719ad5ef8a2ce62bf35f23d8c37e';
 module.exports = node;
diff --git a/app/MMB/src/components/Deeplink.js b/app/MMB/src/components/Deeplink.js
index 430adc42..95dc2829 100644
--- a/app/MMB/src/components/Deeplink.js
+++ b/app/MMB/src/components/Deeplink.js
@@ -5,14 +5,14 @@ import { WebView } from '@kiwicom/mobile-shared';
 import { graphql, PrivateApiRenderer } from '@kiwicom/mobile-relay';
 import idx from 'idx';
 
+import BookingDetailContext from '../context/BookingDetailContext';
 import type {
   DirectAccessURLValues,
   DeeplinkQueryResponse,
 } from './__generated__/DeeplinkQuery.graphql';
 
 type Props = {|
-  bookingID: string,
-  to?: DirectAccessURLValues,
+  +to?: DirectAccessURLValues,
 |};
 
 export default class Deeplink extends React.Component<Props> {
@@ -25,22 +25,26 @@ export default class Deeplink extends React.Component<Props> {
   };
 
   render = () => (
-    <PrivateApiRenderer
-      render={this.renderInnerComponent}
-      query={graphql`
-        query DeeplinkQuery(
-          $bookingId: ID!
-          $deeplinkTo: DirectAccessURLValues
-        ) {
-          booking(id: $bookingId) {
-            directAccessURL(deeplinkTo: $deeplinkTo)
-          }
-        }
-      `}
-      variables={{
-        bookingId: this.props.bookingID,
-        deeplinkTo: this.props.to,
-      }}
-    />
+    <BookingDetailContext.Consumer>
+      {({ bookingId }) => (
+        <PrivateApiRenderer
+          render={this.renderInnerComponent}
+          query={graphql`
+            query DeeplinkQuery(
+              $bookingId: ID!
+              $deeplinkTo: DirectAccessURLValues
+            ) {
+              booking(id: $bookingId) {
+                directAccessURL(deeplinkTo: $deeplinkTo)
+              }
+            }
+          `}
+          variables={{
+            bookingId: bookingId,
+            deeplinkTo: this.props.to,
+          }}
+        />
+      )}
+    </BookingDetailContext.Consumer>
   );
 }
diff --git a/app/MMB/src/components/HeaderShareButton.js b/app/MMB/src/components/HeaderShareButton.js
new file mode 100644
index 00000000..2ccedce0
--- /dev/null
+++ b/app/MMB/src/components/HeaderShareButton.js
@@ -0,0 +1,64 @@
+// @flow
+
+import * as React from 'react';
+import { Share, Platform } from 'react-native';
+import {
+  TextIcon,
+  HeaderRightButton,
+  Color,
+  StyleSheet,
+} from '@kiwicom/mobile-shared';
+import { DateFormatter, GetDeviceLocale } from '@kiwicom/mobile-localization';
+
+import BookingDetailContext from '../context/BookingDetailContext';
+
+type PropsWithContext = {|
+  +arrivalCityId: string,
+  +arrivalTime: Date,
+|};
+
+class HeaderShareButton extends React.Component<PropsWithContext> {
+  onPress = () => {
+    const lang = GetDeviceLocale().split('-')[0] || 'en';
+    const message = `https://kiwi.com/share?date=${DateFormatter(
+      this.props.arrivalTime,
+    ).formatForMachine()}&city_id=${
+      this.props.arrivalCityId
+    }&source=manageMyBooking&lang=${lang}&type=flight`;
+
+    Platform.select({
+      ios: Share.share({ url: message }),
+      android: Share.share({ message }),
+    });
+  };
+
+  render = () => (
+    <HeaderRightButton onPress={this.onPress}>
+      {Platform.select({
+        ios: <TextIcon code="&#xe083;" style={styles.icon} />,
+        android: <TextIcon code="&#xe068;" style={styles.icon} />,
+      })}
+    </HeaderRightButton>
+  );
+}
+
+export default function HeaderShareButtonWithContext() {
+  return (
+    <BookingDetailContext.Consumer>
+      {({ arrivalCityId, arrivalTime }) => (
+        <HeaderShareButton
+          arrivalCityId={arrivalCityId}
+          arrivalTime={arrivalTime}
+        />
+      )}
+    </BookingDetailContext.Consumer>
+  );
+}
+
+const styles = StyleSheet.create({
+  icon: {
+    fontSize: 21,
+    color: Color.brand,
+    alignSelf: 'flex-start',
+  },
+});
diff --git a/app/MMB/src/components/Invoice.js b/app/MMB/src/components/Invoice.js
index ac821937..8c95f21c 100644
--- a/app/MMB/src/components/Invoice.js
+++ b/app/MMB/src/components/Invoice.js
@@ -7,13 +7,10 @@ import { Translation } from '@kiwicom/mobile-localization';
 import PdfViewer from '@kiwicom/mobile-pdf';
 import idx from 'idx';
 
+import BookingDetailContext from '../context/BookingDetailContext';
 import type { InvoiceQueryResponse } from './__generated__/InvoiceQuery.graphql';
 
-type Props = {|
-  bookingID: string,
-|};
-
-export default class Invoice extends React.Component<Props> {
+export default class Invoice extends React.Component<{||}> {
   renderInnerComponent = (renderProps: InvoiceQueryResponse) => {
     const uri = idx(renderProps, _ => _.booking.assets.invoiceUrl);
 
@@ -36,20 +33,24 @@ export default class Invoice extends React.Component<Props> {
   };
 
   render = () => (
-    <PrivateApiRenderer
-      render={this.renderInnerComponent}
-      query={graphql`
-        query InvoiceQuery($bookingId: ID!) {
-          booking(id: $bookingId) {
-            assets {
-              invoiceUrl
+    <BookingDetailContext.Consumer>
+      {({ bookingId }) => (
+        <PrivateApiRenderer
+          render={this.renderInnerComponent}
+          query={graphql`
+            query InvoiceQuery($bookingId: ID!) {
+              booking(id: $bookingId) {
+                assets {
+                  invoiceUrl
+                }
+              }
             }
-          }
-        }
-      `}
-      variables={{
-        bookingId: this.props.bookingID,
-      }}
-    />
+          `}
+          variables={{
+            bookingId: bookingId,
+          }}
+        />
+      )}
+    </BookingDetailContext.Consumer>
   );
 }
diff --git a/app/MMB/src/components/header/Header.js b/app/MMB/src/components/header/Header.js
index 36ed089c..f223dbee 100644
--- a/app/MMB/src/components/header/Header.js
+++ b/app/MMB/src/components/header/Header.js
@@ -10,10 +10,11 @@ import { SeparatorFullWidth } from '../Separators';
 import StatusBar from './StatusBar';
 import TripInfo from './TripInfo';
 import HeaderImage from './HeaderImage';
+import HeaderPlaceholder from './HeaderPlaceholder';
 import type { Header as BookingType } from './__generated__/Header.graphql';
 
 type Props = {|
-  data: BookingType,
+  +data: BookingType,
 |};
 
 const Header = (props: Props) => {
@@ -22,9 +23,7 @@ const Header = (props: Props) => {
 
   return (
     <React.Fragment>
-      {isPastBooking ? (
-        <HeaderImage data={booking} />
-      ) : null /* TODO: Return explore city component */}
+      {isPastBooking ? <HeaderImage data={booking} /> : <HeaderPlaceholder />}
       <View style={styleSheet.wrapper}>
         <StatusBar data={booking} />
         <View style={styleSheet.separator}>
@@ -52,8 +51,6 @@ const styleSheet = StyleSheet.create({
   wrapper: {
     backgroundColor: Color.white,
     padding: 10,
-    borderStartWidth: 5,
-    borderColor: Color.brand,
   },
   separator: {
     marginVertical: 10,
diff --git a/app/MMB/src/components/header/HeaderImage.js b/app/MMB/src/components/header/HeaderImage.js
index 96434525..065cc4b8 100644
--- a/app/MMB/src/components/header/HeaderImage.js
+++ b/app/MMB/src/components/header/HeaderImage.js
@@ -1,19 +1,19 @@
 // @flow
 
 import * as React from 'react';
-import { View } from 'react-native';
 import { StyleSheet, NetworkImage } from '@kiwicom/mobile-shared';
 import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
 import idx from 'idx';
 
+import HeaderPlaceholder from './HeaderPlaceholder';
 import type { HeaderImage as HeaderImageType } from './__generated__/HeaderImage.graphql';
 
 type Props = {|
-  data: HeaderImageType,
+  +data: HeaderImageType,
 |};
 
 const HeaderImage = (props: Props) => (
-  <View style={styles.container}>
+  <HeaderPlaceholder>
     <NetworkImage
       source={{
         uri: idx(props.data, _ => _.destinationImageUrl),
@@ -21,7 +21,7 @@ const HeaderImage = (props: Props) => (
       style={styles.image}
       resizeMode="cover"
     />
-  </View>
+  </HeaderPlaceholder>
 );
 
 export default createFragmentContainer(
@@ -34,12 +34,5 @@ export default createFragmentContainer(
 );
 
 const styles = StyleSheet.create({
-  container: {
-    height: 140,
-    width: '100%',
-    overflow: 'hidden',
-  },
-  image: {
-    ...StyleSheet.absoluteFillObject,
-  },
+  image: StyleSheet.absoluteFillObject,
 });
diff --git a/app/MMB/src/components/header/HeaderPlaceholder.js b/app/MMB/src/components/header/HeaderPlaceholder.js
new file mode 100644
index 00000000..98a3d45a
--- /dev/null
+++ b/app/MMB/src/components/header/HeaderPlaceholder.js
@@ -0,0 +1,22 @@
+// @flow
+
+import * as React from 'react';
+import { View } from 'react-native';
+import { StyleSheet, Color } from '@kiwicom/mobile-shared';
+
+type Props = {|
+  +children?: React.Node,
+|};
+
+export default function HeaderPlaceholder(props: Props) {
+  return <View style={styles.container}>{props.children}</View>;
+}
+
+const styles = StyleSheet.create({
+  container: {
+    backgroundColor: Color.brandLight,
+    height: 140,
+    width: '100%',
+    overflow: 'hidden',
+  },
+});
diff --git a/app/MMB/src/components/header/TripInfo.js b/app/MMB/src/components/header/TripInfo.js
index 1cddc10b..e23042eb 100644
--- a/app/MMB/src/components/header/TripInfo.js
+++ b/app/MMB/src/components/header/TripInfo.js
@@ -1,7 +1,6 @@
 // @flow
 
 import * as React from 'react';
-import { View } from 'react-native';
 import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
 import idx from 'idx';
 
@@ -19,13 +18,13 @@ function TripInfo(props: Props) {
   const type = idx(data, _ => _.type);
 
   return (
-    <View>
+    <React.Fragment>
       {type === 'ONE_WAY' && <TripInfoOneWay data={data && data.oneWay} />}
       {type === 'RETURN' && <TripInfoReturn data={data && data.return} />}
       {type === 'MULTICITY' && (
         <TripInfoMulticity data={data && data.multicity} />
       )}
-    </View>
+    </React.Fragment>
   );
 }
 
diff --git a/app/MMB/src/components/header/TripInfoMulticity.js b/app/MMB/src/components/header/TripInfoMulticity.js
index 81dec925..abaaa778 100644
--- a/app/MMB/src/components/header/TripInfoMulticity.js
+++ b/app/MMB/src/components/header/TripInfoMulticity.js
@@ -1,9 +1,12 @@
 // @flow
 
 import * as React from 'react';
+import { View } from 'react-native';
 import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
+import { StyleSheet } from '@kiwicom/mobile-shared';
 import idx from 'idx';
 
+import { SeparatorFullWidth } from '../Separators';
 import TripCities from './TripCities';
 import TripTimes from './TripTimes';
 import type { TripInfoMulticity as TripInfoMulticityType } from './__generated__/TripInfoMulticity.graphql';
@@ -14,16 +17,34 @@ type Props = {|
 
 function TripInfoMulticity(props: Props) {
   const trips = idx(props, _ => _.data.trips) || [];
+  let separator = null;
 
-  return trips.map((trip, index) => (
-    <React.Fragment key={index}>
-      {/* ONE_WAY because we are printing it for every leg (one way) */}
-      <TripCities data={trip} type="ONE_WAY" />
-      <TripTimes data={trip} />
-    </React.Fragment>
-  ));
+  return trips.map((trip, index) => {
+    const row = (
+      <React.Fragment key={index}>
+        {/* ONE_WAY because we are printing it for every leg (one way) */}
+        {separator}
+        <TripCities data={trip} type="ONE_WAY" />
+        <TripTimes data={trip} />
+      </React.Fragment>
+    );
+
+    separator = (
+      <View style={styleSheet.separatorWrapper}>
+        <SeparatorFullWidth />
+      </View>
+    );
+
+    return row;
+  });
 }
 
+const styleSheet = StyleSheet.create({
+  separatorWrapper: {
+    marginVertical: 10,
+  },
+});
+
 export default createFragmentContainer(
   TripInfoMulticity,
   graphql`
diff --git a/app/MMB/src/context/BookingDetailContext.js b/app/MMB/src/context/BookingDetailContext.js
index af15fc31..908e4e8e 100644
--- a/app/MMB/src/context/BookingDetailContext.js
+++ b/app/MMB/src/context/BookingDetailContext.js
@@ -2,9 +2,20 @@
 
 import * as React from 'react';
 
+type BookingDetail = {|
+  +isPastBooking: boolean,
+  +bookingId: string,
+  +arrivalCityId: string,
+  +arrivalTime: Date,
+|};
 const defaultState = {
   isPastBooking: false,
   bookingId: '',
+  arrivalCityId: '',
+  arrivalTime: new Date(),
+  actions: {
+    setBookingDetail: () => {},
+  },
 };
 
 const { Consumer, Provider: ContextProvider } = React.createContext({
@@ -13,13 +24,13 @@ const { Consumer, Provider: ContextProvider } = React.createContext({
 
 type Props = {|
   +children: React.Node,
-  +isPastBooking: boolean,
-  +bookingId: string,
 |};
 
 type State = {|
-  +isPastBooking: boolean,
-  +bookingId: string,
+  ...BookingDetail,
+  +actions: {|
+    +setBookingDetail: (booking: BookingDetail) => void,
+  |},
 |};
 
 class Provider extends React.Component<Props, State> {
@@ -27,11 +38,22 @@ class Provider extends React.Component<Props, State> {
     super(props);
 
     this.state = {
-      isPastBooking: props.isPastBooking,
-      bookingId: props.bookingId,
+      ...defaultState,
+      actions: {
+        setBookingDetail: this.setBookingDetail,
+      },
     };
   }
 
+  setBookingDetail = ({
+    isPastBooking,
+    bookingId,
+    arrivalCityId,
+    arrivalTime,
+  }: BookingDetail) => {
+    this.setState({ isPastBooking, bookingId, arrivalCityId, arrivalTime });
+  };
+
   render = () => (
     <ContextProvider value={this.state}>{this.props.children}</ContextProvider>
   );
diff --git a/app/MMB/src/menuGroups/PassengerMenuGroup.js b/app/MMB/src/menuGroups/PassengerMenuGroup.js
deleted file mode 100644
index 35938c54..00000000
--- a/app/MMB/src/menuGroups/PassengerMenuGroup.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// @flow
-
-import * as React from 'react';
-import { TextIcon } from '@kiwicom/mobile-shared';
-import { Translation } from '@kiwicom/mobile-localization';
-
-import TitledMenuGroup from '../components/menu/TitledMenuGroup';
-import MenuItem from '../components/menu/MenuItem';
-
-type Props = {|
-  openSubmenu: (activeId: string, menuId: string) => void,
-  activeId: string,
-|};
-
-export default class PassengerMenuGroup extends React.Component<Props> {
-  handleOnPassengerDetailPress = () => {
-    this.props.openSubmenu(
-      'mmb.main_menu.passengers.passenger_details',
-      'mmb.passenger_detail',
-    );
-  };
-
-  render = () => (
-    <TitledMenuGroup title={<Translation id="mmb.main_menu.passengers" />}>
-      <MenuItem
-        onPress={this.handleOnPassengerDetailPress}
-        title={<Translation id="mmb.main_menu.details" />}
-        isActive={
-          this.props.activeId === 'mmb.main_menu.passengers.passenger_details'
-        }
-        icon={<TextIcon code="&#xe087;" />}
-      />
-    </TitledMenuGroup>
-  );
-}
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/Passenger.js b/app/MMB/src/menuGroups/passengerMenuGroup/Passenger.js
new file mode 100644
index 00000000..770dbd50
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/Passenger.js
@@ -0,0 +1,56 @@
+// @flow
+
+import * as React from 'react';
+import { View } from 'react-native';
+import { StyleSheet, Text, Color } from '@kiwicom/mobile-shared';
+import { Translation, DateFormatter } from '@kiwicom/mobile-localization';
+import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
+import idx from 'idx';
+
+import type { Passenger as PassengerType } from './__generated__/Passenger.graphql';
+
+type Props = {|
+  +data: PassengerType,
+|};
+
+const Passenger = ({ data }: Props) => {
+  const title = idx(data, _ => _.title) || '';
+  const fullName = idx(data, _ => _.fullName) || '';
+  const birthday = new Date(idx(data, _ => _.birthday) || '');
+
+  return (
+    <View style={styles.passenger}>
+      <Text style={styles.passengerText}>
+        <Translation passThrough={`${title}. ${fullName}`} />
+      </Text>
+      <Text style={[styles.passengerText, styles.passengerBirthday]}>
+        <Translation passThrough={DateFormatter(birthday).formatToBirthday()} />
+      </Text>
+    </View>
+  );
+};
+
+export default createFragmentContainer(
+  Passenger,
+  graphql`
+    fragment Passenger on Passenger {
+      fullName
+      title
+      birthday
+    }
+  `,
+);
+
+const styles = StyleSheet.create({
+  passenger: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    marginBottom: 16,
+  },
+  passengerText: {
+    fontSize: 12,
+  },
+  passengerBirthday: {
+    color: Color.textLight,
+  },
+});
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuDetail.js b/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuDetail.js
new file mode 100644
index 00000000..8a56b72b
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuDetail.js
@@ -0,0 +1,49 @@
+// @flow
+
+import * as React from 'react';
+import { View } from 'react-native';
+import { StyleSheet } from '@kiwicom/mobile-shared';
+import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
+import idx from 'idx';
+
+import Passenger from './Passenger';
+import Visa from './Visa';
+import type { PassengerMenuDetail as Booking } from './__generated__/PassengerMenuDetail.graphql';
+
+type Props = {|
+  +data: Booking,
+|};
+
+const PassengerMenuDetail = (props: Props) => {
+  const passengers = idx(props.data, _ => _.passengers) || [];
+
+  return (
+    <React.Fragment>
+      <View style={styles.container}>
+        {passengers.map(passenger => (
+          <Passenger data={passenger} key={idx(passenger, _ => _.databaseId)} />
+        ))}
+      </View>
+      <Visa data={props.data} />
+    </React.Fragment>
+  );
+};
+
+export default createFragmentContainer(
+  PassengerMenuDetail,
+  graphql`
+    fragment PassengerMenuDetail on Booking {
+      ...Visa
+      passengers {
+        databaseId
+        ...Passenger
+      }
+    }
+  `,
+);
+
+const styles = StyleSheet.create({
+  container: {
+    padding: 15,
+  },
+});
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuGroup.js b/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuGroup.js
new file mode 100644
index 00000000..be49e27e
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/PassengerMenuGroup.js
@@ -0,0 +1,51 @@
+// @flow
+
+import * as React from 'react';
+import { TextIcon } from '@kiwicom/mobile-shared';
+import { Translation } from '@kiwicom/mobile-localization';
+import { createFragmentContainer, graphql } from '@kiwicom/mobile-relay';
+
+import TitledMenuGroup from '../../components/menu/TitledMenuGroup';
+import MenuItem from '../../components/menu/MenuItem';
+import PassengerMenuDetail from './PassengerMenuDetail';
+import type { PassengerMenuGroup as Boooking } from './__generated__/PassengerMenuGroup.graphql';
+
+type Props = {|
+  +openSubmenu: (activeId: string, menuId: string) => void,
+  +activeId: string,
+  +data: Boooking,
+|};
+
+class PassengerMenuGroup extends React.Component<Props> {
+  handleOnPassengerDetailPress = () => {
+    this.props.openSubmenu(
+      'mmb.main_menu.passengers.passenger_details',
+      'mmb.passenger_detail',
+    );
+  };
+
+  render = () => (
+    <React.Fragment>
+      <TitledMenuGroup title={<Translation id="mmb.main_menu.passengers" />}>
+        <MenuItem
+          onPress={this.handleOnPassengerDetailPress}
+          title={<Translation id="mmb.main_menu.details" />}
+          isActive={
+            this.props.activeId === 'mmb.main_menu.passengers.passenger_details'
+          }
+          icon={<TextIcon code="&#xe087;" />}
+        />
+      </TitledMenuGroup>
+      <PassengerMenuDetail data={this.props.data} />
+    </React.Fragment>
+  );
+}
+
+export default createFragmentContainer(
+  PassengerMenuGroup,
+  graphql`
+    fragment PassengerMenuGroup on Booking {
+      ...PassengerMenuDetail
+    }
+  `,
+);
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/Visa.js b/app/MMB/src/menuGroups/passengerMenuGroup/Visa.js
new file mode 100644
index 00000000..ccb00e36
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/Visa.js
@@ -0,0 +1,73 @@
+// @flow
+
+import * as React from 'react';
+import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
+import idx from 'idx';
+import { Translation } from '@kiwicom/mobile-localization';
+
+import Alert from '../../components/alert/Alert';
+import type { Visa as BookingType } from './__generated__/Visa.graphql';
+import VisaInformation from '../../scenes/passenger/visa/VisaInformation';
+
+type Props = {|
+  +data: BookingType,
+|};
+
+const Visa = ({ data }: Props) => {
+  const passengers = idx(data, _ => _.passengers) || [];
+  const { requiredIn, warningIn } = passengers.reduce(
+    (acc, curr) => {
+      const requiredIn = idx(curr, _ => _.visaInformation.requiredIn) || [];
+      const warningIn = idx(curr, _ => _.visaInformation.warningIn) || [];
+      return {
+        requiredIn: [
+          ...acc.requiredIn,
+          ...requiredIn.map(item => idx(item, _ => _.name) || ''),
+        ],
+        warningIn: [
+          ...acc.warningIn,
+          ...warningIn.map(item => idx(item, _ => _.name) || ''),
+        ],
+      };
+    },
+    {
+      requiredIn: [],
+      warningIn: [],
+    },
+  );
+
+  return (
+    <VisaInformation requiredIn={requiredIn} warningIn={warningIn}>
+      {requiredIn.length > 0 && (
+        <Alert
+          type="danger"
+          title={<Translation id="mmb.visa_state.visa_is_required" />}
+        />
+      )}
+      {warningIn.length > 0 && (
+        <Alert
+          type="warning"
+          title={<Translation id="mmb.visa_state.visa_may_be_required" />}
+        />
+      )}
+    </VisaInformation>
+  );
+};
+
+export default createFragmentContainer(
+  Visa,
+  graphql`
+    fragment Visa on Booking {
+      passengers {
+        visaInformation {
+          requiredIn {
+            name
+          }
+          warningIn {
+            name
+          }
+        }
+      }
+    }
+  `,
+);
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Passenger.graphql.js b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Passenger.graphql.js
new file mode 100644
index 00000000..aabaa3f3
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Passenger.graphql.js
@@ -0,0 +1,54 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type Passenger$ref: FragmentReference;
+export type Passenger = {|
+  +fullName: ?string,
+  +title: ?string,
+  +birthday: ?any,
+  +$refType: Passenger$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "Passenger",
+  "type": "Passenger",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "fullName",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "title",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "birthday",
+      "args": null,
+      "storageKey": null
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = 'f411bea99514ae48f7d94d47f24444cd';
+module.exports = node;
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuDetail.graphql.js b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuDetail.graphql.js
new file mode 100644
index 00000000..73d9a282
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuDetail.graphql.js
@@ -0,0 +1,65 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+type Passenger$ref = any;
+type Visa$ref = any;
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type PassengerMenuDetail$ref: FragmentReference;
+export type PassengerMenuDetail = {|
+  +passengers: ?$ReadOnlyArray<?{|
+    +databaseId: ?number,
+    +$fragmentRefs: Passenger$ref,
+  |}>,
+  +$fragmentRefs: Visa$ref,
+  +$refType: PassengerMenuDetail$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "PassengerMenuDetail",
+  "type": "Booking",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "FragmentSpread",
+      "name": "Visa",
+      "args": null
+    },
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "passengers",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Passenger",
+      "plural": true,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "databaseId",
+          "args": null,
+          "storageKey": null
+        },
+        {
+          "kind": "FragmentSpread",
+          "name": "Passenger",
+          "args": null
+        }
+      ]
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = 'c618fac829e30c950211943a39729fa5';
+module.exports = node;
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuGroup.graphql.js b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuGroup.graphql.js
new file mode 100644
index 00000000..fea14e0b
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/PassengerMenuGroup.graphql.js
@@ -0,0 +1,37 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+type PassengerMenuDetail$ref = any;
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type PassengerMenuGroup$ref: FragmentReference;
+export type PassengerMenuGroup = {|
+  +$fragmentRefs: PassengerMenuDetail$ref,
+  +$refType: PassengerMenuGroup$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "PassengerMenuGroup",
+  "type": "Booking",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "FragmentSpread",
+      "name": "PassengerMenuDetail",
+      "args": null
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = '9b8e662f51415385f59647023bea3454';
+module.exports = node;
diff --git a/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Visa.graphql.js b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Visa.graphql.js
new file mode 100644
index 00000000..60a7df14
--- /dev/null
+++ b/app/MMB/src/menuGroups/passengerMenuGroup/__generated__/Visa.graphql.js
@@ -0,0 +1,93 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type Visa$ref: FragmentReference;
+export type Visa = {|
+  +passengers: ?$ReadOnlyArray<?{|
+    +visaInformation: ?{|
+      +requiredIn: ?$ReadOnlyArray<?{|
+        +name: ?string
+      |}>,
+      +warningIn: ?$ReadOnlyArray<?{|
+        +name: ?string
+      |}>,
+    |}
+  |}>,
+  +$refType: Visa$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = (function(){
+var v0 = [
+  {
+    "kind": "ScalarField",
+    "alias": null,
+    "name": "name",
+    "args": null,
+    "storageKey": null
+  }
+];
+return {
+  "kind": "Fragment",
+  "name": "Visa",
+  "type": "Booking",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "passengers",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Passenger",
+      "plural": true,
+      "selections": [
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "visaInformation",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Visa",
+          "plural": false,
+          "selections": [
+            {
+              "kind": "LinkedField",
+              "alias": null,
+              "name": "requiredIn",
+              "storageKey": null,
+              "args": null,
+              "concreteType": "Location",
+              "plural": true,
+              "selections": v0
+            },
+            {
+              "kind": "LinkedField",
+              "alias": null,
+              "name": "warningIn",
+              "storageKey": null,
+              "args": null,
+              "concreteType": "Location",
+              "plural": true,
+              "selections": v0
+            }
+          ]
+        }
+      ]
+    }
+  ]
+};
+})();
+// prettier-ignore
+(node/*: any*/).hash = '59cd91887a5fe7fb18a8767ca74e6f2d';
+module.exports = node;
diff --git a/app/MMB/src/navigation/DetailScreen.js b/app/MMB/src/navigation/DetailScreen.js
index 9317619a..4b872656 100644
--- a/app/MMB/src/navigation/DetailScreen.js
+++ b/app/MMB/src/navigation/DetailScreen.js
@@ -5,8 +5,9 @@ import { HeaderTitle, type NavigationType } from '@kiwicom/mobile-navigation';
 import { AdaptableLayout } from '@kiwicom/mobile-shared';
 import { Translation } from '@kiwicom/mobile-localization';
 
+import HeaderShareButton from '../components/HeaderShareButton';
 import Layout from '../components/Layout';
-import MainMenu from '../MainMenu';
+import MainMenuContainer from '../MainMenuContainer';
 import HelpSubmenu, { HelpSubmenuItems } from '../scenes/help';
 import OtherSubmenu, { OtherSubmenuItems } from '../scenes/Other';
 import FlightServices, {
@@ -14,17 +15,6 @@ import FlightServices, {
 } from '../scenes/flightServices/FlightServices';
 import TripServices from '../scenes/TripServices';
 import PassengerDetailContainer from '../scenes/passenger/PassengerDetailContainer';
-import BookingDetailContext from '../context/BookingDetailContext';
-
-type Props = {|
-  isPastBooking: boolean,
-  bookingId: string,
-  navigation: NavigationType,
-|};
-
-type State = {|
-  activeContainerComponent: string,
-|};
 
 export const MenuComponents = {
   'mmb.passenger_detail': {
@@ -82,6 +72,14 @@ export const MenuComponents = {
   ...OtherSubmenuItems,
 };
 
+type Props = {|
+  +navigation: NavigationType,
+|};
+
+type State = {|
+  activeContainerComponent: string,
+|};
+
 export default class DetailsScreen extends React.Component<Props, State> {
   state = {
     activeContainerComponent: 'mmb.passenger_detail',
@@ -103,6 +101,7 @@ export default class DetailsScreen extends React.Component<Props, State> {
           <Translation id="mmb.main_menu.title" />
         </HeaderTitle>
       ),
+      headerRight: <HeaderShareButton />,
     };
   };
 
@@ -114,12 +113,8 @@ export default class DetailsScreen extends React.Component<Props, State> {
     this.props.navigation.navigate({
       routeName: key,
       key: `key-${key}`,
-      params: {
-        bookingId: this.props.bookingId,
-      },
     });
   };
-
   /**
    * Just change container content for tablets. It's also necessary to change
    * the header title.
@@ -141,25 +136,21 @@ export default class DetailsScreen extends React.Component<Props, State> {
     ).screen;
 
     return (
-      <BookingDetailContext.Provider
-        isPastBooking={this.props.isPastBooking}
-        bookingId={this.props.bookingId}
-      >
-        <Layout
-          menuComponent={
-            <AdaptableLayout.Consumer
-              renderOnWide={<MainMenu openMenu={this.changeContentOnTablet} />}
-              renderOnNarrow={<MainMenu openMenu={this.openMenuOnMobile} />}
-            />
-          }
-          containerComponent={
-            <ContainerComponent
-              navigation={this.props.navigation}
-              bookingId={this.props.bookingId}
-            />
-          }
-        />
-      </BookingDetailContext.Provider>
+      <Layout
+        menuComponent={
+          <AdaptableLayout.Consumer
+            renderOnWide={
+              <MainMenuContainer openMenu={this.changeContentOnTablet} />
+            }
+            renderOnNarrow={
+              <MainMenuContainer openMenu={this.openMenuOnMobile} />
+            }
+          />
+        }
+        containerComponent={
+          <ContainerComponent navigation={this.props.navigation} />
+        }
+      />
     );
   };
 }
diff --git a/app/MMB/src/scenes/FlightServices.js b/app/MMB/src/scenes/FlightServices.js
index c61d64b0..d5651b15 100644
--- a/app/MMB/src/scenes/FlightServices.js
+++ b/app/MMB/src/scenes/FlightServices.js
@@ -14,8 +14,7 @@ import MenuItem from '../components/menu/MenuItem';
 import Deeplink from '../components/Deeplink';
 
 type Props = {|
-  bookingId: string,
-  navigation: NavigationType,
+  +navigation: NavigationType,
 |};
 
 export default class FlightServices extends React.Component<Props> {
@@ -23,9 +22,6 @@ export default class FlightServices extends React.Component<Props> {
     this.props.navigation.navigate({
       routeName: key,
       key: `key-${key}`,
-      params: {
-        bookingId: this.props.bookingId,
-      },
     });
   };
 
@@ -91,39 +87,35 @@ export default class FlightServices extends React.Component<Props> {
   );
 }
 
-type SubmenuProps = {|
-  bookingId: string,
-|};
-
 export const FlightServicesSubmenuItems = {
   'mmb.flight_services.checked_baggage': {
-    screen: function OpenCheckedBaggage({ bookingId }: SubmenuProps) {
-      return <Deeplink to="BAGS" bookingID={bookingId} />;
+    screen: function OpenCheckedBaggage() {
+      return <Deeplink to="BAGS" />;
     },
   },
   'mmb.flight_services.allocated_seating': {
-    screen: function OpenAllocatedSeating({ bookingId }: SubmenuProps) {
-      return <Deeplink to="SEATING" bookingID={bookingId} />;
+    screen: function OpenAllocatedSeating() {
+      return <Deeplink to="SEATING" />;
     },
   },
   'mmb.flight_services.sports_equipment': {
-    screen: function OpenSportsEquipment({ bookingId }: SubmenuProps) {
-      return <Deeplink to="SPORT_EQUIPMENT" bookingID={bookingId} />;
+    screen: function OpenSportsEquipment() {
+      return <Deeplink to="SPORT_EQUIPMENT" />;
     },
   },
   'mmb.flight_services.musical_equipment': {
-    screen: function OpenMusicalEquipment({ bookingId }: SubmenuProps) {
-      return <Deeplink to="MUSICAL_EQUIPMENT" bookingID={bookingId} />;
+    screen: function OpenMusicalEquipment() {
+      return <Deeplink to="MUSICAL_EQUIPMENT" />;
     },
   },
   'mmb.flight_services.special_assistance': {
-    screen: function OpenSpecialAssistance({ bookingId }: SubmenuProps) {
-      return <Deeplink to="ASSISTANCE" bookingID={bookingId} />;
+    screen: function OpenSpecialAssistance() {
+      return <Deeplink to="ASSISTANCE" />;
     },
   },
   'mmb.flight_services.pets': {
-    screen: function OpenPetPassengers({ bookingId }: SubmenuProps) {
-      return <Deeplink to="PETS" bookingID={bookingId} />;
+    screen: function OpenPetPassengers() {
+      return <Deeplink to="PETS" />;
     },
   },
 };
diff --git a/app/MMB/src/scenes/Other.js b/app/MMB/src/scenes/Other.js
index 73b34d63..2672e3ed 100644
--- a/app/MMB/src/scenes/Other.js
+++ b/app/MMB/src/scenes/Other.js
@@ -15,8 +15,7 @@ import Invoice from '../components/Invoice';
 import { SeparatorFullWidth, SeparatorTrimmed } from '../components/Separators';
 
 type Props = {|
-  bookingId: string,
-  navigation: NavigationType,
+  +navigation: NavigationType,
 |};
 
 export default class Other extends React.Component<Props> {
@@ -24,9 +23,6 @@ export default class Other extends React.Component<Props> {
     this.props.navigation.navigate({
       routeName: key,
       key: `key-${key}`,
-      params: {
-        bookingId: this.props.bookingId,
-      },
     });
   };
 
@@ -70,24 +66,20 @@ export default class Other extends React.Component<Props> {
   );
 }
 
-type SubmenuProps = {|
-  bookingId: string,
-|};
-
 export const OtherSubmenuItems = {
   'mmb.other.invoice': {
-    screen: function OtherSubmenuOpenInvoice({ bookingId }: SubmenuProps) {
-      return <Invoice bookingID={bookingId} />;
+    screen: function OtherSubmenuOpenInvoice() {
+      return <Invoice />;
     },
   },
   'mmb.other.open': {
-    screen: function OtherSubmenuOpenOnWeb({ bookingId }: SubmenuProps) {
-      return <Deeplink bookingID={bookingId} />;
+    screen: function OtherSubmenuOpenOnWeb() {
+      return <Deeplink />;
     },
   },
   'mmb.other.refund': {
-    screen: function OtherSubmenuRefundForm({ bookingId }: SubmenuProps) {
-      return <Deeplink to="REFUND" bookingID={bookingId} />;
+    screen: function OtherSubmenuRefundForm() {
+      return <Deeplink to="REFUND" />;
     },
   },
 };
diff --git a/app/MMB/src/scenes/flightServices/FlightServices.js b/app/MMB/src/scenes/flightServices/FlightServices.js
index e135be8f..af0f034c 100644
--- a/app/MMB/src/scenes/flightServices/FlightServices.js
+++ b/app/MMB/src/scenes/flightServices/FlightServices.js
@@ -6,10 +6,9 @@ import { PrivateApiRenderer, graphql } from '@kiwicom/mobile-relay';
 import FlightServicesMenuGroup from './FlightServicesMenuGroup';
 import type { FlightServicesQueryResponse } from './__generated__/FlightServicesQuery.graphql';
 import Deeplink from '../../components/Deeplink';
+import BookingDetailContext from '../../context/BookingDetailContext';
 
-type Props = {|
-  bookingId: string,
-|};
+type Props = {||};
 
 export default class FlightServices extends React.Component<Props> {
   renderInner = (renderProps: FlightServicesQueryResponse) => (
@@ -17,55 +16,55 @@ export default class FlightServices extends React.Component<Props> {
   );
 
   render = () => (
-    <PrivateApiRenderer
-      query={graphql`
-        query FlightServicesQuery($id: ID!) {
-          booking(id: $id) {
-            ...FlightServicesMenuGroup_bookedServices
-          }
-        }
-      `}
-      variables={{
-        id: this.props.bookingId,
-      }}
-      render={this.renderInner}
-    />
+    <BookingDetailContext.Consumer>
+      {({ bookingId }) => (
+        <PrivateApiRenderer
+          query={graphql`
+            query FlightServicesQuery($id: ID!) {
+              booking(id: $id) {
+                ...FlightServicesMenuGroup_bookedServices
+              }
+            }
+          `}
+          variables={{
+            id: bookingId,
+          }}
+          render={this.renderInner}
+        />
+      )}
+    </BookingDetailContext.Consumer>
   );
 }
 
-type SubmenuProps = {|
-  bookingId: string,
-|};
-
 export const FlightServicesSubmenuItems = {
   'mmb.flight_services.checked_baggage': {
-    screen: function OpenCheckedBaggage({ bookingId }: SubmenuProps) {
-      return <Deeplink to="BAGS" bookingID={bookingId} />;
+    screen: function OpenCheckedBaggage() {
+      return <Deeplink to="BAGS" />;
     },
   },
   'mmb.flight_services.allocated_seating': {
-    screen: function OpenAllocatedSeating({ bookingId }: SubmenuProps) {
-      return <Deeplink to="SEATING" bookingID={bookingId} />;
+    screen: function OpenAllocatedSeating() {
+      return <Deeplink to="SEATING" />;
     },
   },
   'mmb.flight_services.sports_equipment': {
-    screen: function OpenSportsEquipment({ bookingId }: SubmenuProps) {
-      return <Deeplink to="SPORT_EQUIPMENT" bookingID={bookingId} />;
+    screen: function OpenSportsEquipment() {
+      return <Deeplink to="SPORT_EQUIPMENT" />;
     },
   },
   'mmb.flight_services.musical_equipment': {
-    screen: function OpenMusicalEquipment({ bookingId }: SubmenuProps) {
-      return <Deeplink to="MUSICAL_EQUIPMENT" bookingID={bookingId} />;
+    screen: function OpenMusicalEquipment() {
+      return <Deeplink to="MUSICAL_EQUIPMENT" />;
     },
   },
   'mmb.flight_services.special_assistance': {
-    screen: function OpenSpecialAssistance({ bookingId }: SubmenuProps) {
-      return <Deeplink to="ASSISTANCE" bookingID={bookingId} />;
+    screen: function OpenSpecialAssistance() {
+      return <Deeplink to="ASSISTANCE" />;
     },
   },
   'mmb.flight_services.pets': {
-    screen: function OpenPetPassengers({ bookingId }: SubmenuProps) {
-      return <Deeplink to="PETS" bookingID={bookingId} />;
+    screen: function OpenPetPassengers() {
+      return <Deeplink to="PETS" />;
     },
   },
 };
diff --git a/app/MMB/src/scenes/list/__generated__/FlightListContainerQuery.graphql.js b/app/MMB/src/scenes/list/__generated__/FlightListContainerQuery.graphql.js
index 2ae09101..01a9362c 100644
--- a/app/MMB/src/scenes/list/__generated__/FlightListContainerQuery.graphql.js
+++ b/app/MMB/src/scenes/list/__generated__/FlightListContainerQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 45e9c19bdc5c54d636d54f6b18e34778
+ * @relayHash 9554b4b5d03231ea48f1eec254a5de52
  */
 
 /* eslint-disable */
@@ -106,6 +106,8 @@ fragment CityImage_image on BookingInterface {
 
 fragment CityImage_arrival on RouteStop {
   ...FromToRow_arrival
+  cityId
+  time
 }
 
 fragment CityImage_departure on RouteStop {
@@ -207,6 +209,13 @@ v7 = {
   "storageKey": null
 },
 v8 = {
+  "kind": "ScalarField",
+  "alias": null,
+  "name": "time",
+  "args": null,
+  "storageKey": null
+},
+v9 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "airport",
@@ -235,17 +244,11 @@ v8 = {
     }
   ]
 },
-v9 = [
-  {
-    "kind": "ScalarField",
-    "alias": null,
-    "name": "time",
-    "args": null,
-    "storageKey": null
-  },
-  v8
+v10 = [
+  v8,
+  v9
 ],
-v10 = {
+v11 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "departure",
@@ -253,12 +256,20 @@ v10 = {
   "args": null,
   "concreteType": "RouteStop",
   "plural": false,
-  "selections": v9
+  "selections": v10
 },
-v11 = [
+v12 = [
+  v9,
+  {
+    "kind": "ScalarField",
+    "alias": null,
+    "name": "cityId",
+    "args": null,
+    "storageKey": null
+  },
   v8
 ],
-v12 = {
+v13 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "arrival",
@@ -266,9 +277,9 @@ v12 = {
   "args": null,
   "concreteType": "RouteStop",
   "plural": false,
-  "selections": v11
+  "selections": v12
 },
-v13 = [
+v14 = [
   {
     "kind": "LinkedField",
     "alias": null,
@@ -318,8 +329,8 @@ v13 = [
                 "concreteType": "Trip",
                 "plural": false,
                 "selections": [
-                  v10,
-                  v12
+                  v11,
+                  v13
                 ]
               },
               v2
@@ -348,8 +359,8 @@ v13 = [
                 "concreteType": "Trip",
                 "plural": false,
                 "selections": [
-                  v12,
-                  v10
+                  v13,
+                  v11
                 ]
               },
               v2
@@ -377,7 +388,7 @@ v13 = [
                 "args": null,
                 "concreteType": "RouteStop",
                 "plural": false,
-                "selections": v11
+                "selections": v12
               },
               {
                 "kind": "LinkedField",
@@ -387,7 +398,7 @@ v13 = [
                 "args": null,
                 "concreteType": "RouteStop",
                 "plural": false,
-                "selections": v9
+                "selections": v10
               },
               v2
             ]
@@ -402,7 +413,7 @@ return {
   "operationKind": "query",
   "name": "FlightListContainerQuery",
   "id": null,
-  "text": "query FlightListContainerQuery {\n  future: allBookings(only: FUTURE) {\n    ...FlightListContainer_future\n  }\n  past: allBookings(only: PAST) {\n    ...FlightListContainer_past\n  }\n}\n\nfragment FlightListContainer_future on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightListContainer_past on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightList on BookingConnection {\n  edges {\n    node {\n      id\n      type\n      oneWay {\n        ...OneWayFlight_booking\n        id\n      }\n      return {\n        ...ReturnFlight_booking\n        id\n      }\n      multicity {\n        ...MulticityFlight_booking\n        id\n      }\n    }\n  }\n}\n\nfragment OneWayFlight_booking on BookingOneWay {\n  ...CityImage_image\n  trip {\n    departure {\n      ...CityImage_departure\n    }\n    arrival {\n      ...CityImage_arrival\n    }\n  }\n}\n\nfragment ReturnFlight_booking on BookingReturn {\n  ...CityImage_image\n  outbound {\n    arrival {\n      ...CityImage_arrival\n    }\n    departure {\n      ...CityImage_departure\n    }\n  }\n}\n\nfragment MulticityFlight_booking on BookingMulticity {\n  ...CityImage_image\n  end {\n    ...CityImage_arrival\n  }\n  start {\n    ...CityImage_departure\n  }\n}\n\nfragment CityImage_image on BookingInterface {\n  databaseId\n  passengerCount\n  isPastBooking\n  destinationImageUrl(dimensions: _375x165)\n  ...ImageBadges\n}\n\nfragment CityImage_arrival on RouteStop {\n  ...FromToRow_arrival\n}\n\nfragment CityImage_departure on RouteStop {\n  ...DateAndPassengerCount_departure\n  ...FromToRow_departure\n}\n\nfragment DateAndPassengerCount_departure on RouteStop {\n  time\n}\n\nfragment FromToRow_departure on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment FromToRow_arrival on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment ImageBadges on BookingInterface {\n  status\n  databaseId\n  isPastBooking\n}\n",
+  "text": "query FlightListContainerQuery {\n  future: allBookings(only: FUTURE) {\n    ...FlightListContainer_future\n  }\n  past: allBookings(only: PAST) {\n    ...FlightListContainer_past\n  }\n}\n\nfragment FlightListContainer_future on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightListContainer_past on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightList on BookingConnection {\n  edges {\n    node {\n      id\n      type\n      oneWay {\n        ...OneWayFlight_booking\n        id\n      }\n      return {\n        ...ReturnFlight_booking\n        id\n      }\n      multicity {\n        ...MulticityFlight_booking\n        id\n      }\n    }\n  }\n}\n\nfragment OneWayFlight_booking on BookingOneWay {\n  ...CityImage_image\n  trip {\n    departure {\n      ...CityImage_departure\n    }\n    arrival {\n      ...CityImage_arrival\n    }\n  }\n}\n\nfragment ReturnFlight_booking on BookingReturn {\n  ...CityImage_image\n  outbound {\n    arrival {\n      ...CityImage_arrival\n    }\n    departure {\n      ...CityImage_departure\n    }\n  }\n}\n\nfragment MulticityFlight_booking on BookingMulticity {\n  ...CityImage_image\n  end {\n    ...CityImage_arrival\n  }\n  start {\n    ...CityImage_departure\n  }\n}\n\nfragment CityImage_image on BookingInterface {\n  databaseId\n  passengerCount\n  isPastBooking\n  destinationImageUrl(dimensions: _375x165)\n  ...ImageBadges\n}\n\nfragment CityImage_arrival on RouteStop {\n  ...FromToRow_arrival\n  cityId\n  time\n}\n\nfragment CityImage_departure on RouteStop {\n  ...DateAndPassengerCount_departure\n  ...FromToRow_departure\n}\n\nfragment DateAndPassengerCount_departure on RouteStop {\n  time\n}\n\nfragment FromToRow_departure on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment FromToRow_arrival on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment ImageBadges on BookingInterface {\n  status\n  databaseId\n  isPastBooking\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
@@ -458,7 +469,7 @@ return {
         "args": v0,
         "concreteType": "BookingConnection",
         "plural": false,
-        "selections": v13
+        "selections": v14
       },
       {
         "kind": "LinkedField",
@@ -468,7 +479,7 @@ return {
         "args": v1,
         "concreteType": "BookingConnection",
         "plural": false,
-        "selections": v13
+        "selections": v14
       }
     ]
   }
diff --git a/app/MMB/src/scenes/list/__generated__/FlightsQuery.graphql.js b/app/MMB/src/scenes/list/__generated__/FlightsQuery.graphql.js
index 05aedab7..28f930ab 100644
--- a/app/MMB/src/scenes/list/__generated__/FlightsQuery.graphql.js
+++ b/app/MMB/src/scenes/list/__generated__/FlightsQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 15420c45c91501d12f199feb796f0fa2
+ * @relayHash c3031b1059688bc1e53c43d409694cdf
  */
 
 /* eslint-disable */
@@ -106,6 +106,8 @@ fragment CityImage_image on BookingInterface {
 
 fragment CityImage_arrival on RouteStop {
   ...FromToRow_arrival
+  cityId
+  time
 }
 
 fragment CityImage_departure on RouteStop {
@@ -207,6 +209,13 @@ v7 = {
   "storageKey": null
 },
 v8 = {
+  "kind": "ScalarField",
+  "alias": null,
+  "name": "time",
+  "args": null,
+  "storageKey": null
+},
+v9 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "airport",
@@ -235,17 +244,11 @@ v8 = {
     }
   ]
 },
-v9 = [
-  {
-    "kind": "ScalarField",
-    "alias": null,
-    "name": "time",
-    "args": null,
-    "storageKey": null
-  },
-  v8
+v10 = [
+  v8,
+  v9
 ],
-v10 = {
+v11 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "departure",
@@ -253,12 +256,20 @@ v10 = {
   "args": null,
   "concreteType": "RouteStop",
   "plural": false,
-  "selections": v9
+  "selections": v10
 },
-v11 = [
+v12 = [
+  v9,
+  {
+    "kind": "ScalarField",
+    "alias": null,
+    "name": "cityId",
+    "args": null,
+    "storageKey": null
+  },
   v8
 ],
-v12 = {
+v13 = {
   "kind": "LinkedField",
   "alias": null,
   "name": "arrival",
@@ -266,9 +277,9 @@ v12 = {
   "args": null,
   "concreteType": "RouteStop",
   "plural": false,
-  "selections": v11
+  "selections": v12
 },
-v13 = [
+v14 = [
   {
     "kind": "LinkedField",
     "alias": null,
@@ -318,8 +329,8 @@ v13 = [
                 "concreteType": "Trip",
                 "plural": false,
                 "selections": [
-                  v10,
-                  v12
+                  v11,
+                  v13
                 ]
               },
               v2
@@ -348,8 +359,8 @@ v13 = [
                 "concreteType": "Trip",
                 "plural": false,
                 "selections": [
-                  v12,
-                  v10
+                  v13,
+                  v11
                 ]
               },
               v2
@@ -377,7 +388,7 @@ v13 = [
                 "args": null,
                 "concreteType": "RouteStop",
                 "plural": false,
-                "selections": v11
+                "selections": v12
               },
               {
                 "kind": "LinkedField",
@@ -387,7 +398,7 @@ v13 = [
                 "args": null,
                 "concreteType": "RouteStop",
                 "plural": false,
-                "selections": v9
+                "selections": v10
               },
               v2
             ]
@@ -402,7 +413,7 @@ return {
   "operationKind": "query",
   "name": "FlightsQuery",
   "id": null,
-  "text": "query FlightsQuery {\n  future: allBookings(only: FUTURE) {\n    ...FlightListContainer_future\n  }\n  past: allBookings(only: PAST) {\n    ...FlightListContainer_past\n  }\n}\n\nfragment FlightListContainer_future on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightListContainer_past on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightList on BookingConnection {\n  edges {\n    node {\n      id\n      type\n      oneWay {\n        ...OneWayFlight_booking\n        id\n      }\n      return {\n        ...ReturnFlight_booking\n        id\n      }\n      multicity {\n        ...MulticityFlight_booking\n        id\n      }\n    }\n  }\n}\n\nfragment OneWayFlight_booking on BookingOneWay {\n  ...CityImage_image\n  trip {\n    departure {\n      ...CityImage_departure\n    }\n    arrival {\n      ...CityImage_arrival\n    }\n  }\n}\n\nfragment ReturnFlight_booking on BookingReturn {\n  ...CityImage_image\n  outbound {\n    arrival {\n      ...CityImage_arrival\n    }\n    departure {\n      ...CityImage_departure\n    }\n  }\n}\n\nfragment MulticityFlight_booking on BookingMulticity {\n  ...CityImage_image\n  end {\n    ...CityImage_arrival\n  }\n  start {\n    ...CityImage_departure\n  }\n}\n\nfragment CityImage_image on BookingInterface {\n  databaseId\n  passengerCount\n  isPastBooking\n  destinationImageUrl(dimensions: _375x165)\n  ...ImageBadges\n}\n\nfragment CityImage_arrival on RouteStop {\n  ...FromToRow_arrival\n}\n\nfragment CityImage_departure on RouteStop {\n  ...DateAndPassengerCount_departure\n  ...FromToRow_departure\n}\n\nfragment DateAndPassengerCount_departure on RouteStop {\n  time\n}\n\nfragment FromToRow_departure on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment FromToRow_arrival on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment ImageBadges on BookingInterface {\n  status\n  databaseId\n  isPastBooking\n}\n",
+  "text": "query FlightsQuery {\n  future: allBookings(only: FUTURE) {\n    ...FlightListContainer_future\n  }\n  past: allBookings(only: PAST) {\n    ...FlightListContainer_past\n  }\n}\n\nfragment FlightListContainer_future on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightListContainer_past on BookingConnection {\n  ...FlightList\n}\n\nfragment FlightList on BookingConnection {\n  edges {\n    node {\n      id\n      type\n      oneWay {\n        ...OneWayFlight_booking\n        id\n      }\n      return {\n        ...ReturnFlight_booking\n        id\n      }\n      multicity {\n        ...MulticityFlight_booking\n        id\n      }\n    }\n  }\n}\n\nfragment OneWayFlight_booking on BookingOneWay {\n  ...CityImage_image\n  trip {\n    departure {\n      ...CityImage_departure\n    }\n    arrival {\n      ...CityImage_arrival\n    }\n  }\n}\n\nfragment ReturnFlight_booking on BookingReturn {\n  ...CityImage_image\n  outbound {\n    arrival {\n      ...CityImage_arrival\n    }\n    departure {\n      ...CityImage_departure\n    }\n  }\n}\n\nfragment MulticityFlight_booking on BookingMulticity {\n  ...CityImage_image\n  end {\n    ...CityImage_arrival\n  }\n  start {\n    ...CityImage_departure\n  }\n}\n\nfragment CityImage_image on BookingInterface {\n  databaseId\n  passengerCount\n  isPastBooking\n  destinationImageUrl(dimensions: _375x165)\n  ...ImageBadges\n}\n\nfragment CityImage_arrival on RouteStop {\n  ...FromToRow_arrival\n  cityId\n  time\n}\n\nfragment CityImage_departure on RouteStop {\n  ...DateAndPassengerCount_departure\n  ...FromToRow_departure\n}\n\nfragment DateAndPassengerCount_departure on RouteStop {\n  time\n}\n\nfragment FromToRow_departure on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment FromToRow_arrival on RouteStop {\n  airport {\n    city {\n      name\n    }\n  }\n}\n\nfragment ImageBadges on BookingInterface {\n  status\n  databaseId\n  isPastBooking\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
@@ -458,7 +469,7 @@ return {
         "args": v0,
         "concreteType": "BookingConnection",
         "plural": false,
-        "selections": v13
+        "selections": v14
       },
       {
         "kind": "LinkedField",
@@ -468,7 +479,7 @@ return {
         "args": v1,
         "concreteType": "BookingConnection",
         "plural": false,
-        "selections": v13
+        "selections": v14
       }
     ]
   }
diff --git a/app/MMB/src/scenes/list/cityImage/CityImage.js b/app/MMB/src/scenes/list/cityImage/CityImage.js
index 0243f942..c6d254e3 100644
--- a/app/MMB/src/scenes/list/cityImage/CityImage.js
+++ b/app/MMB/src/scenes/list/cityImage/CityImage.js
@@ -17,27 +17,38 @@ import idx from 'idx';
 import FromToRow from './FromToRow';
 import DateAndPassengerCount from './DateAndPassengerCount';
 import ImageBadges from './ImageBadges';
+import BookingDetailContext from '../../../context/BookingDetailContext';
 import type { CityImage_arrival as ArrivalType } from './__generated__/CityImage_arrival.graphql';
 import type { CityImage_departure as DepartureType } from './__generated__/CityImage_departure.graphql';
 import type { CityImage_image as ImageType } from './__generated__/CityImage_image.graphql';
 
-type Props = {|
-  image: ImageType,
-  arrival: ArrivalType,
-  departure: DepartureType,
-  type: 'RETURN' | 'ONE_WAY' | 'MULTICITY',
-  navigation: NavigationType,
+type PropsWithContext = {|
+  ...Props,
+  +setBookingDetail: (booking: {|
+    isPastBooking: boolean,
+    bookingId: string,
+    arrivalCityId: string,
+    arrivalTime: Date,
+  |}) => void,
 |};
 
-class CityImage extends React.Component<Props> {
+class CityImage extends React.Component<PropsWithContext> {
   goToDetail = () => {
+    const bookingId = idx(this.props.image, _ => _.databaseId) || '';
+    const isPastBooking = Boolean(idx(this.props.image, _ => _.isPastBooking));
+    const arrivalCityId = idx(this.props.arrival, _ => _.cityId) || '';
+    const arrivalTime = idx(this.props.arrival, _ => _.time) || '';
+
+    this.props.setBookingDetail({
+      bookingId: bookingId.toString(),
+      isPastBooking,
+      arrivalCityId,
+      arrivalTime: new Date(arrivalTime),
+    });
+
     this.props.navigation.navigate({
       routeName: 'DetailScreen',
       key: 'key-DetailScreen',
-      params: {
-        bookingId: idx(this.props.image, _ => _.databaseId),
-        isPastBooking: idx(this.props.image, _ => _.isPastBooking),
-      },
     });
   };
 
@@ -71,8 +82,24 @@ class CityImage extends React.Component<Props> {
   );
 }
 
+type Props = {|
+  +image: ImageType,
+  +arrival: ArrivalType,
+  +departure: DepartureType,
+  +type: 'RETURN' | 'ONE_WAY' | 'MULTICITY',
+  +navigation: NavigationType,
+|};
+
+const CityImageWithContext = (props: Props) => (
+  <BookingDetailContext.Consumer>
+    {({ actions: { setBookingDetail } }) => (
+      <CityImage {...props} setBookingDetail={setBookingDetail} />
+    )}
+  </BookingDetailContext.Consumer>
+);
+
 export default createFragmentContainer(
-  withNavigation(CityImage),
+  withNavigation(CityImageWithContext),
   graphql`
     fragment CityImage_image on BookingInterface {
       databaseId
@@ -84,6 +111,8 @@ export default createFragmentContainer(
 
     fragment CityImage_arrival on RouteStop {
       ...FromToRow_arrival
+      cityId
+      time
     }
 
     fragment CityImage_departure on RouteStop {
diff --git a/app/MMB/src/scenes/list/cityImage/__generated__/CityImage_arrival.graphql.js b/app/MMB/src/scenes/list/cityImage/__generated__/CityImage_arrival.graphql.js
index 2a706ed4..2c74d824 100644
--- a/app/MMB/src/scenes/list/cityImage/__generated__/CityImage_arrival.graphql.js
+++ b/app/MMB/src/scenes/list/cityImage/__generated__/CityImage_arrival.graphql.js
@@ -12,6 +12,8 @@ type FromToRow_arrival$ref = any;
 import type { FragmentReference } from "relay-runtime";
 declare export opaque type CityImage_arrival$ref: FragmentReference;
 export type CityImage_arrival = {|
+  +cityId: ?string,
+  +time: ?any,
   +$fragmentRefs: FromToRow_arrival$ref,
   +$refType: CityImage_arrival$ref,
 |};
@@ -29,9 +31,23 @@ const node/*: ConcreteFragment*/ = {
       "kind": "FragmentSpread",
       "name": "FromToRow_arrival",
       "args": null
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "cityId",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "time",
+      "args": null,
+      "storageKey": null
     }
   ]
 };
 // prettier-ignore
-(node/*: any*/).hash = '83aa66339e287f7815c8ab1825e69a46';
+(node/*: any*/).hash = 'b0ac23d857e7bda1db54b32ddc8d19ee';
 module.exports = node;
diff --git a/app/MMB/src/scenes/passenger/Passenger.js b/app/MMB/src/scenes/passenger/Passenger.js
index f4599466..9488405b 100644
--- a/app/MMB/src/scenes/passenger/Passenger.js
+++ b/app/MMB/src/scenes/passenger/Passenger.js
@@ -10,6 +10,8 @@ import startCase from 'lodash/startCase';
 
 import { SeparatorTrimmed } from '../../components/Separators';
 import VisaInformation from './visa/VisaInformation';
+import VisaWarning from './visa/VisaWarning';
+import VisaRequired from './visa/VisaRequired';
 import type { Passenger_passenger as PassengerType } from './__generated__/Passenger_passenger.graphql';
 import MenuGroup from '../../components/menu/MenuGroup';
 import PassengerMenuItem from './PassengerMenuItem';
@@ -19,7 +21,7 @@ const Row = ({ children }: {| children: React.Node |}) => (
 );
 
 type Props = {|
-  passenger: PassengerType,
+  +passenger: PassengerType,
 |};
 
 export const Passenger = ({ passenger }: Props) => {
@@ -32,6 +34,11 @@ export const Passenger = ({ passenger }: Props) => {
     (idx(passenger, _ => _.insuranceType) || '').toLowerCase(),
   );
 
+  let requiredIn = idx(passenger, _ => _.visaInformation.requiredIn) || [];
+  requiredIn = requiredIn.map(item => idx(item, _ => _.name) || '');
+  let warningIn = idx(passenger, _ => _.visaInformation.warningIn) || [];
+  warningIn = warningIn.map(item => idx(item, _ => _.name) || '');
+
   return (
     <SimpleCard style={styles.card}>
       <MenuGroup
@@ -64,7 +71,10 @@ export const Passenger = ({ passenger }: Props) => {
             value={<Translation passThrough={insuranceType} />}
           />
         </Row>
-        <VisaInformation visa={passenger} />
+        <VisaInformation requiredIn={requiredIn} warningIn={warningIn}>
+          <VisaRequired countries={requiredIn} />
+          <VisaWarning countries={warningIn} />
+        </VisaInformation>
       </MenuGroup>
     </SimpleCard>
   );
@@ -82,7 +92,14 @@ export default createFragmentContainer(
         idNumber
       }
       insuranceType
-      ...VisaInformation_visa
+      visaInformation {
+        requiredIn {
+          name
+        }
+        warningIn {
+          name
+        }
+      }
     }
   `,
 );
diff --git a/app/MMB/src/scenes/passenger/PassengerDetailContainer.js b/app/MMB/src/scenes/passenger/PassengerDetailContainer.js
index 1a6c8c26..9e8c3bf3 100644
--- a/app/MMB/src/scenes/passenger/PassengerDetailContainer.js
+++ b/app/MMB/src/scenes/passenger/PassengerDetailContainer.js
@@ -4,11 +4,10 @@ import * as React from 'react';
 import { graphql, PrivateApiRenderer } from '@kiwicom/mobile-relay';
 
 import PassengerDetail from './PassengerDetail';
+import BookingDetailContext from '../../context/BookingDetailContext';
 import type { PassengerDetailContainerQuery } from './__generated__/PassengerDetailContainerQuery.graphql';
 
-type Props = {|
-  bookingId: string,
-|};
+type Props = {||};
 
 export default class PassengerDetailContainer extends React.Component<Props> {
   renderInner = (renderProps: PassengerDetailContainerQuery) => {
@@ -16,16 +15,20 @@ export default class PassengerDetailContainer extends React.Component<Props> {
   };
 
   render = () => (
-    <PrivateApiRenderer
-      query={graphql`
-        query PassengerDetailContainerQuery($id: ID!) {
-          booking(id: $id) {
-            ...PassengerDetail_booking
-          }
-        }
-      `}
-      variables={{ id: this.props.bookingId }}
-      render={this.renderInner}
-    />
+    <BookingDetailContext.Consumer>
+      {({ bookingId }) => (
+        <PrivateApiRenderer
+          query={graphql`
+            query PassengerDetailContainerQuery($id: ID!) {
+              booking(id: $id) {
+                ...PassengerDetail_booking
+              }
+            }
+          `}
+          variables={{ id: bookingId }}
+          render={this.renderInner}
+        />
+      )}
+    </BookingDetailContext.Consumer>
   );
 }
diff --git a/app/MMB/src/scenes/passenger/__generated__/PassengerDetailContainerQuery.graphql.js b/app/MMB/src/scenes/passenger/__generated__/PassengerDetailContainerQuery.graphql.js
index 5564ca8a..0f163d67 100644
--- a/app/MMB/src/scenes/passenger/__generated__/PassengerDetailContainerQuery.graphql.js
+++ b/app/MMB/src/scenes/passenger/__generated__/PassengerDetailContainerQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash c144d30eb06f4848b6aa94c5ae6ffbac
+ * @relayHash 5b2ca5d4830f6250a2fcb44099522966
  */
 
 /* eslint-disable */
@@ -56,10 +56,6 @@ fragment Passenger_passenger on Passenger {
     idNumber
   }
   insuranceType
-  ...VisaInformation_visa
-}
-
-fragment VisaInformation_visa on Passenger {
   visaInformation {
     requiredIn {
       name
@@ -109,7 +105,7 @@ return {
   "operationKind": "query",
   "name": "PassengerDetailContainerQuery",
   "id": null,
-  "text": "query PassengerDetailContainerQuery(\n  $id: ID!\n) {\n  booking(id: $id) {\n    ...PassengerDetail_booking\n    id\n  }\n}\n\nfragment PassengerDetail_booking on Booking {\n  databaseId\n  contactDetails {\n    ...ContactDetails_contactDetails\n  }\n  passengers {\n    databaseId\n    ...Passenger_passenger\n  }\n}\n\nfragment ContactDetails_contactDetails on BookingContactDetails {\n  phone\n  email\n}\n\nfragment Passenger_passenger on Passenger {\n  fullName\n  title\n  birthday\n  nationality\n  travelDocument {\n    idNumber\n  }\n  insuranceType\n  ...VisaInformation_visa\n}\n\nfragment VisaInformation_visa on Passenger {\n  visaInformation {\n    requiredIn {\n      name\n    }\n    warningIn {\n      name\n    }\n  }\n}\n",
+  "text": "query PassengerDetailContainerQuery(\n  $id: ID!\n) {\n  booking(id: $id) {\n    ...PassengerDetail_booking\n    id\n  }\n}\n\nfragment PassengerDetail_booking on Booking {\n  databaseId\n  contactDetails {\n    ...ContactDetails_contactDetails\n  }\n  passengers {\n    databaseId\n    ...Passenger_passenger\n  }\n}\n\nfragment ContactDetails_contactDetails on BookingContactDetails {\n  phone\n  email\n}\n\nfragment Passenger_passenger on Passenger {\n  fullName\n  title\n  birthday\n  nationality\n  travelDocument {\n    idNumber\n  }\n  insuranceType\n  visaInformation {\n    requiredIn {\n      name\n    }\n    warningIn {\n      name\n    }\n  }\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/passenger/__generated__/PassengerDetailQuery.graphql.js b/app/MMB/src/scenes/passenger/__generated__/PassengerDetailQuery.graphql.js
index 905c5cc1..c0c78755 100644
--- a/app/MMB/src/scenes/passenger/__generated__/PassengerDetailQuery.graphql.js
+++ b/app/MMB/src/scenes/passenger/__generated__/PassengerDetailQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 0319badcafb3be87682541923e719980
+ * @relayHash 939cda06d5e623f766e87f98d05fecb6
  */
 
 /* eslint-disable */
@@ -56,10 +56,6 @@ fragment Passenger_passenger on Passenger {
     idNumber
   }
   insuranceType
-  ...VisaInformation_visa
-}
-
-fragment VisaInformation_visa on Passenger {
   visaInformation {
     requiredIn {
       name
@@ -109,7 +105,7 @@ return {
   "operationKind": "query",
   "name": "PassengerDetailQuery",
   "id": null,
-  "text": "query PassengerDetailQuery(\n  $id: ID!\n) {\n  booking(id: $id) {\n    ...PassengerDetail_booking\n    id\n  }\n}\n\nfragment PassengerDetail_booking on Booking {\n  databaseId\n  contactDetails {\n    ...ContactDetails_contactDetails\n  }\n  passengers {\n    databaseId\n    ...Passenger_passenger\n  }\n}\n\nfragment ContactDetails_contactDetails on BookingContactDetails {\n  phone\n  email\n}\n\nfragment Passenger_passenger on Passenger {\n  fullName\n  title\n  birthday\n  nationality\n  travelDocument {\n    idNumber\n  }\n  insuranceType\n  ...VisaInformation_visa\n}\n\nfragment VisaInformation_visa on Passenger {\n  visaInformation {\n    requiredIn {\n      name\n    }\n    warningIn {\n      name\n    }\n  }\n}\n",
+  "text": "query PassengerDetailQuery(\n  $id: ID!\n) {\n  booking(id: $id) {\n    ...PassengerDetail_booking\n    id\n  }\n}\n\nfragment PassengerDetail_booking on Booking {\n  databaseId\n  contactDetails {\n    ...ContactDetails_contactDetails\n  }\n  passengers {\n    databaseId\n    ...Passenger_passenger\n  }\n}\n\nfragment ContactDetails_contactDetails on BookingContactDetails {\n  phone\n  email\n}\n\nfragment Passenger_passenger on Passenger {\n  fullName\n  title\n  birthday\n  nationality\n  travelDocument {\n    idNumber\n  }\n  insuranceType\n  visaInformation {\n    requiredIn {\n      name\n    }\n    warningIn {\n      name\n    }\n  }\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/passenger/__generated__/Passenger_passenger.graphql.js b/app/MMB/src/scenes/passenger/__generated__/Passenger_passenger.graphql.js
index deab3a37..4d1604e2 100644
--- a/app/MMB/src/scenes/passenger/__generated__/Passenger_passenger.graphql.js
+++ b/app/MMB/src/scenes/passenger/__generated__/Passenger_passenger.graphql.js
@@ -8,7 +8,6 @@
 
 /*::
 import type { ConcreteFragment } from 'relay-runtime';
-type VisaInformation_visa$ref = any;
 export type InsuranceType = "NONE" | "TRAVEL_BASIC" | "TRAVEL_PLUS" | "%future added value";
 import type { FragmentReference } from "relay-runtime";
 declare export opaque type Passenger_passenger$ref: FragmentReference;
@@ -21,13 +20,30 @@ export type Passenger_passenger = {|
     +idNumber: ?string
   |},
   +insuranceType: ?InsuranceType,
-  +$fragmentRefs: VisaInformation_visa$ref,
+  +visaInformation: ?{|
+    +requiredIn: ?$ReadOnlyArray<?{|
+      +name: ?string
+    |}>,
+    +warningIn: ?$ReadOnlyArray<?{|
+      +name: ?string
+    |}>,
+  |},
   +$refType: Passenger_passenger$ref,
 |};
 */
 
 
-const node/*: ConcreteFragment*/ = {
+const node/*: ConcreteFragment*/ = (function(){
+var v0 = [
+  {
+    "kind": "ScalarField",
+    "alias": null,
+    "name": "name",
+    "args": null,
+    "storageKey": null
+  }
+];
+return {
   "kind": "Fragment",
   "name": "Passenger_passenger",
   "type": "Passenger",
@@ -88,12 +104,39 @@ const node/*: ConcreteFragment*/ = {
       "storageKey": null
     },
     {
-      "kind": "FragmentSpread",
-      "name": "VisaInformation_visa",
-      "args": null
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "visaInformation",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Visa",
+      "plural": false,
+      "selections": [
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "requiredIn",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Location",
+          "plural": true,
+          "selections": v0
+        },
+        {
+          "kind": "LinkedField",
+          "alias": null,
+          "name": "warningIn",
+          "storageKey": null,
+          "args": null,
+          "concreteType": "Location",
+          "plural": true,
+          "selections": v0
+        }
+      ]
     }
   ]
 };
+})();
 // prettier-ignore
-(node/*: any*/).hash = 'b2093f050c07c992a8849e420b204ea4';
+(node/*: any*/).hash = '716c048f169a8890e173d03b07ef1d92';
 module.exports = node;
diff --git a/app/MMB/src/scenes/passenger/visa/VisaInformation.js b/app/MMB/src/scenes/passenger/visa/VisaInformation.js
index 035ef43a..53ad3033 100644
--- a/app/MMB/src/scenes/passenger/visa/VisaInformation.js
+++ b/app/MMB/src/scenes/passenger/visa/VisaInformation.js
@@ -1,13 +1,8 @@
 // @flow
 
 import * as React from 'react';
-import { graphql, createFragmentContainer } from '@kiwicom/mobile-relay';
-import idx from 'idx';
 
-import VisaRequired from './VisaRequired';
 import VisaOk from './VisaOk';
-import VisaWarning from './VisaWarning';
-import type { VisaInformation_visa as VisaType } from './__generated__/VisaInformation_visa.graphql';
 import ManageMyBookingContext from '../../../context/BookingDetailContext';
 
 type PropsWithContext = {|
@@ -15,11 +10,13 @@ type PropsWithContext = {|
   +isPastBooking: boolean,
 |};
 
-export const VisaInformation = (props: PropsWithContext) => {
-  const requiredIn = idx(props.visa, _ => _.visaInformation.requiredIn) || [];
-  const warningIn = idx(props.visa, _ => _.visaInformation.warningIn) || [];
-
-  if (props.isPastBooking) {
+export const VisaInformation = ({
+  requiredIn,
+  warningIn,
+  isPastBooking,
+  children,
+}: PropsWithContext) => {
+  if (isPastBooking) {
     return null;
   }
 
@@ -27,20 +24,13 @@ export const VisaInformation = (props: PropsWithContext) => {
     return <VisaOk />;
   }
 
-  return (
-    <React.Fragment>
-      <VisaRequired
-        countries={requiredIn.map(country => idx(country, _ => _.name) || '')}
-      />
-      <VisaWarning
-        countries={warningIn.map(country => idx(country, _ => _.name) || '')}
-      />
-    </React.Fragment>
-  );
+  return children;
 };
 
 type Props = {|
-  +visa: VisaType,
+  +requiredIn: $ReadOnlyArray<string>,
+  +warningIn: $ReadOnlyArray<string>,
+  +children: React.Node,
 |};
 
 const VisaInformationWithContext = (props: Props) => (
@@ -51,18 +41,4 @@ const VisaInformationWithContext = (props: Props) => (
   </ManageMyBookingContext.Consumer>
 );
 
-export default createFragmentContainer(
-  VisaInformationWithContext,
-  graphql`
-    fragment VisaInformation_visa on Passenger {
-      visaInformation {
-        requiredIn {
-          name
-        }
-        warningIn {
-          name
-        }
-      }
-    }
-  `,
-);
+export default VisaInformationWithContext;
diff --git a/app/MMB/src/scenes/passenger/visa/VisaRequired.js b/app/MMB/src/scenes/passenger/visa/VisaRequired.js
index 240fd51e..bc901562 100644
--- a/app/MMB/src/scenes/passenger/visa/VisaRequired.js
+++ b/app/MMB/src/scenes/passenger/visa/VisaRequired.js
@@ -7,7 +7,7 @@ import { StyleSheet, Text } from '@kiwicom/mobile-shared';
 import Alert from '../../../components/alert/Alert';
 
 type Props = {|
-  countries: string[],
+  +countries: $ReadOnlyArray<string>,
 |};
 
 export default function VisaRequired(props: Props) {
@@ -17,7 +17,7 @@ export default function VisaRequired(props: Props) {
   return (
     <Alert
       type="danger"
-      title={<Translation id="mmb.visa_state.visa_is_required" />}
+      title={<Translation id="mmb.visa_state.visa_is_required_in" />}
     >
       {props.countries.map(country => (
         <Text key={country} style={styles.country}>
diff --git a/app/MMB/src/scenes/passenger/visa/VisaWarning.js b/app/MMB/src/scenes/passenger/visa/VisaWarning.js
index adb08dc0..ce7307b3 100644
--- a/app/MMB/src/scenes/passenger/visa/VisaWarning.js
+++ b/app/MMB/src/scenes/passenger/visa/VisaWarning.js
@@ -7,7 +7,7 @@ import { StyleSheet, Text } from '@kiwicom/mobile-shared';
 import Alert from '../../../components/alert/Alert';
 
 type Props = {|
-  countries: string[],
+  +countries: $ReadOnlyArray<string>,
 |};
 
 export default function VisaWarning(props: Props) {
@@ -17,7 +17,7 @@ export default function VisaWarning(props: Props) {
   return (
     <Alert
       type="warning"
-      title={<Translation id="mmb.visa_state.visa_may_be_required" />}
+      title={<Translation id="mmb.visa_state.visa_may_be_required_in" />}
     >
       {props.countries.map(country => (
         <Text key={country} style={styles.country}>
diff --git a/app/MMB/src/scenes/passenger/visa/__generated__/VisaInformation_visa.graphql.js b/app/MMB/src/scenes/passenger/visa/__generated__/VisaInformation_visa.graphql.js
deleted file mode 100644
index c2b6fc58..00000000
--- a/app/MMB/src/scenes/passenger/visa/__generated__/VisaInformation_visa.graphql.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @flow
- */
-
-/* eslint-disable */
-
-'use strict';
-
-/*::
-import type { ConcreteFragment } from 'relay-runtime';
-import type { FragmentReference } from "relay-runtime";
-declare export opaque type VisaInformation_visa$ref: FragmentReference;
-export type VisaInformation_visa = {|
-  +visaInformation: ?{|
-    +requiredIn: ?$ReadOnlyArray<?{|
-      +name: ?string
-    |}>,
-    +warningIn: ?$ReadOnlyArray<?{|
-      +name: ?string
-    |}>,
-  |},
-  +$refType: VisaInformation_visa$ref,
-|};
-*/
-
-
-const node/*: ConcreteFragment*/ = (function(){
-var v0 = [
-  {
-    "kind": "ScalarField",
-    "alias": null,
-    "name": "name",
-    "args": null,
-    "storageKey": null
-  }
-];
-return {
-  "kind": "Fragment",
-  "name": "VisaInformation_visa",
-  "type": "Passenger",
-  "metadata": null,
-  "argumentDefinitions": [],
-  "selections": [
-    {
-      "kind": "LinkedField",
-      "alias": null,
-      "name": "visaInformation",
-      "storageKey": null,
-      "args": null,
-      "concreteType": "Visa",
-      "plural": false,
-      "selections": [
-        {
-          "kind": "LinkedField",
-          "alias": null,
-          "name": "requiredIn",
-          "storageKey": null,
-          "args": null,
-          "concreteType": "Location",
-          "plural": true,
-          "selections": v0
-        },
-        {
-          "kind": "LinkedField",
-          "alias": null,
-          "name": "warningIn",
-          "storageKey": null,
-          "args": null,
-          "concreteType": "Location",
-          "plural": true,
-          "selections": v0
-        }
-      ]
-    }
-  ]
-};
-})();
-// prettier-ignore
-(node/*: any*/).hash = '389022b56a00315a1f58e4dd6d439fb7';
-module.exports = node;
diff --git a/app/hotels/src/navigation/allHotels/MapHeaderButton.android.js b/app/hotels/src/navigation/allHotels/MapHeaderButton.android.js
index 786222ac..e1fa022f 100644
--- a/app/hotels/src/navigation/allHotels/MapHeaderButton.android.js
+++ b/app/hotels/src/navigation/allHotels/MapHeaderButton.android.js
@@ -1,11 +1,11 @@
 // @flow
 
 import * as React from 'react';
-import { HeaderRightButton } from '@kiwicom/mobile-shared';
+import { HeaderRightButton, Color, Icon } from '@kiwicom/mobile-shared';
 import RNTooltips from 'react-native-tooltips';
 
 type Props = {|
-  onPress: () => void,
+  +onPress: () => void,
 |};
 
 type State = {|
@@ -38,23 +38,22 @@ export default class MapHeaderButton extends React.Component<Props, State> {
     });
   };
 
-  render = () => [
-    <HeaderRightButton
-      key="header-right-button"
-      onPress={this.onPress}
-      onLongPress={this.onLongPress}
-    />,
-    <RNTooltips
-      key="header-right-button-tooltip"
-      text="Open map"
-      visible={this.state.isTooltipVisible}
-      reference={this.state.buttonReference}
-      corner={100}
-      tintColor="#505c5e"
-      arrow={false}
-      textSize={16}
-      shadow={true}
-      onHide={this.onTooltipClose}
-    />,
-  ];
+  render = () => (
+    <React.Fragment>
+      <HeaderRightButton onPress={this.onPress} onLongPress={this.onLongPress}>
+        <Icon name="map" size={24} color={Color.brand} />
+      </HeaderRightButton>
+      <RNTooltips
+        text="Open map"
+        visible={this.state.isTooltipVisible}
+        reference={this.state.buttonReference}
+        corner={100}
+        tintColor="#505c5e"
+        arrow={false}
+        textSize={16}
+        shadow={true}
+        onHide={this.onTooltipClose}
+      />
+    </React.Fragment>
+  );
 }
diff --git a/app/hotels/src/navigation/allHotels/MapHeaderButton.ios.js b/app/hotels/src/navigation/allHotels/MapHeaderButton.ios.js
index 9f5ab1b0..7c2c913c 100644
--- a/app/hotels/src/navigation/allHotels/MapHeaderButton.ios.js
+++ b/app/hotels/src/navigation/allHotels/MapHeaderButton.ios.js
@@ -1,12 +1,16 @@
 // @flow
 
 import * as React from 'react';
-import { HeaderRightButton } from '@kiwicom/mobile-shared';
+import { HeaderRightButton, Icon, Color } from '@kiwicom/mobile-shared';
 
 type Props = {|
-  onPress: () => void,
+  +onPress: () => void,
 |};
 
 export default function MapHeaderButton(props: Props) {
-  return <HeaderRightButton onPress={props.onPress} />;
+  return (
+    <HeaderRightButton onPress={props.onPress}>
+      <Icon name="map" size={24} color={Color.brand} />
+    </HeaderRightButton>
+  );
 }
diff --git a/ios/RNKiwiMobile/RNKiwiGestureController.m b/ios/RNKiwiMobile/RNKiwiGestureController.m
index 51be7e12..c8a8f596 100644
--- a/ios/RNKiwiMobile/RNKiwiGestureController.m
+++ b/ios/RNKiwiMobile/RNKiwiGestureController.m
@@ -11,12 +11,14 @@ RCT_EXPORT_MODULE(RNKiwiGestureController);
 
 RCT_EXPORT_METHOD(disableGestures:(NSString *)moduleName) {
   [[NSNotificationCenter defaultCenter] postNotificationName:RNKiwiDisableGestures
-                                                      object:moduleName];
+                                                      object:nil
+                                                    userInfo:@{ @"moduleName": moduleName }];
 }
 
 RCT_EXPORT_METHOD(enableGestures:(NSString *)moduleName) {
   [[NSNotificationCenter defaultCenter] postNotificationName:RNKiwiEnableGestures
-                                                      object:moduleName];
+                                                      object:nil
+                                                    userInfo:@{ @"moduleName": moduleName }];
 }
 
 @end
diff --git a/ios/RNKiwiMobile/RNKiwiViewController.h b/ios/RNKiwiMobile/RNKiwiViewController.h
index 60dc6198..55563298 100644
--- a/ios/RNKiwiMobile/RNKiwiViewController.h
+++ b/ios/RNKiwiMobile/RNKiwiViewController.h
@@ -8,6 +8,8 @@
 
 - (nonnull instancetype)initWithOptions:(nonnull id<RNKiwiOptions>)properties;
 - (nonnull instancetype)init NS_UNAVAILABLE;
+- (BOOL)isInteractivePopGestureAllowed;
+
 
 // Delegates
 @property (nonatomic, weak, nullable) id<RNKiwiCurrencyManager> currencyFormatter;
diff --git a/ios/RNKiwiMobile/RNKiwiViewController.m b/ios/RNKiwiMobile/RNKiwiViewController.m
index 4e2de60c..ad0d32d3 100644
--- a/ios/RNKiwiMobile/RNKiwiViewController.m
+++ b/ios/RNKiwiMobile/RNKiwiViewController.m
@@ -15,6 +15,7 @@
 @interface RNKiwiViewController() <RNNavigationDelegate, RNLogger, RNTranslator, RNCurrencyFormatter>
 
 @property (nonatomic, strong) id<RNKiwiOptions> options;
+@property (nonatomic) BOOL isGestureAllowed;
 
 @end
 
@@ -24,12 +25,11 @@
 
 - (instancetype)initWithOptions:(id<RNKiwiOptions>)options {
   self = [super init];
-  [self startObservingGestures];
   if (self) {
     _options = options;
+    _isGestureAllowed = YES;
     
     [self setupReactWrappersWithObject:self];
-    
     [[RNKiwiSharedBridge sharedInstance] initBridgeWithOptions:options];
   }
   
@@ -41,6 +41,11 @@
   [RNNavigationModule setNavigationDelegate:object];
   [RNTranslationManager setTranslator:object];
   [RNCurrencyManager setCurrencyFormatter:object];
+  if (object) {
+    [self startObservingGestures];
+  } else {
+    [self stopObservingGestures];
+  }
 }
 
 #pragma mark - View lifecycle
@@ -57,7 +62,6 @@
   if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
     [self notifyFinish];
     [self setupReactWrappersWithObject:nil];
-    [self stopObservingGestures];
   }
 }
 
@@ -117,34 +121,36 @@
 
 #pragma mark - Gesture Controller Observers
 
-- (void)disableGestures {
-  if ([self.flowDelegate respondsToSelector:@selector(RNKiwiViewControllerDidStartControllingGestures:)]) {
-    [self.flowDelegate RNKiwiViewControllerDidStartControllingGestures:self];
+- (void)disableGestures:(NSNotification *)notification {
+  if ([notification.userInfo[@"moduleName"] isEqualToString:[_options moduleName]]) {
+    _isGestureAllowed = NO;
   }
 }
 
-- (void)enableGestures {
-  if ([self.flowDelegate respondsToSelector:@selector(RNKiwiViewControllerDidStopControllingGestures:)]) {
-    [self.flowDelegate RNKiwiViewControllerDidStopControllingGestures:self];
+- (void)enableGestures:(NSNotification *)notification {
+  if ([notification.userInfo[@"moduleName"] isEqualToString:[_options moduleName]]) {
+    _isGestureAllowed = YES;
   }
 }
 
 - (void)startObservingGestures {
   [[NSNotificationCenter defaultCenter] addObserver:self
-                                           selector:@selector(disableGestures)
+                                           selector:@selector(disableGestures:)
                                                name:RNKiwiDisableGestures
-                                             object:[_options moduleName]];
+                                             object:nil];
   
   [[NSNotificationCenter defaultCenter] addObserver:self
-                                           selector:@selector(enableGestures)
+                                           selector:@selector(enableGestures:)
                                                name:RNKiwiEnableGestures
-                                             object:[_options moduleName]];
+                                             object:nil];
 }
 
 - (void)stopObservingGestures {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 
-
+- (BOOL)isInteractivePopGestureAllowed {
+  return _isGestureAllowed;
+}
 
 @end
diff --git a/ios/RNKiwiMobile/RNKiwiViewControllerFlowDelegate.h b/ios/RNKiwiMobile/RNKiwiViewControllerFlowDelegate.h
index 80fa5abc..c991985a 100644
--- a/ios/RNKiwiMobile/RNKiwiViewControllerFlowDelegate.h
+++ b/ios/RNKiwiMobile/RNKiwiViewControllerFlowDelegate.h
@@ -3,7 +3,5 @@
 @protocol RNKiwiViewControllerFlowDelegate <NSObject>
 @optional
 - (void)RNKiwiViewControllerDidFinish:(nonnull RNKiwiViewController *)viewController;
-- (void)RNKiwiViewControllerDidStartControllingGestures:(nonnull RNKiwiViewController *)viewController;
-- (void)RNKiwiViewControllerDidStopControllingGestures:(nonnull RNKiwiViewController *)viewController;
 
 @end
diff --git a/ios/RNNativePlayground/ViewController.m b/ios/RNNativePlayground/ViewController.m
index 8df168ea..eb7bb372 100644
--- a/ios/RNNativePlayground/ViewController.m
+++ b/ios/RNNativePlayground/ViewController.m
@@ -1,7 +1,9 @@
 #import "ViewController.h"
 #import <RNKiwiMobile/RNKiwiMobile.h>
 
-@interface ViewController () <RNKiwiOptions, RNKiwiCurrencyManager, RNKiwiTranslationProvider, RNKiwiViewControllerFlowDelegate>
+@interface ViewController () <UIGestureRecognizerDelegate, RNKiwiOptions, RNKiwiCurrencyManager, RNKiwiTranslationProvider, RNKiwiViewControllerFlowDelegate>
+
+@property (nonatomic, strong) RNKiwiViewController *vc;
 
 @end
 
@@ -24,12 +26,13 @@
 }
 
 - (IBAction)showHotelsView:(id)sender {
-  RNKiwiViewController *vc = [[RNKiwiViewController alloc] initWithOptions:self];
-  [vc setCurrencyFormatter:self];
-  [vc setTranslationProvider:self];
-  [vc setFlowDelegate:self];
+  __weak typeof(self) weakSelf = self;
+  _vc = [[RNKiwiViewController alloc] initWithOptions:weakSelf];
+  [_vc setCurrencyFormatter:weakSelf];
+  [_vc setTranslationProvider:weakSelf];
+  [_vc setFlowDelegate:weakSelf];
   
-  [[self navigationController] pushViewController:vc animated:YES ];
+  [[self navigationController] pushViewController:_vc animated:YES];
 }
 
 # pragma mark - RNKiwiOptions
@@ -55,6 +58,7 @@
 
 - (void)viewDidAppear:(BOOL)animated {
   self.navigationController.navigationBar.hidden = YES;
+  self.navigationController.interactivePopGestureRecognizer.delegate = self;
 }
 
 # pragma mark - RNKiwiViewControllerFlowDelegate
@@ -63,14 +67,6 @@
   [self.navigationController popViewControllerAnimated:YES];
 }
 
-- (void)RNKiwiViewControllerDidStartControllingGestures:(nonnull RNKiwiViewController *)viewController {
-  self.navigationController.interactivePopGestureRecognizer.enabled = NO;
-}
-
-- (void)RNKiwiViewControllerDidStopControllingGestures:(nonnull RNKiwiViewController *)viewController {
-  self.navigationController.interactivePopGestureRecognizer.enabled = YES;
-}
-
 # pragma mark - RNKiwiCurrencyManager
 
 - (NSString *)formattedPrice:(NSNumber *)price withCurrency:(NSString *)currencyCode {
@@ -84,4 +80,15 @@
   return nil;
 }
 
+#pragma mark - UIGestureRecognizer
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
+  
+  if (self.navigationController.interactivePopGestureRecognizer == gestureRecognizer) {
+    return [_vc isInteractivePopGestureAllowed];
+  }
+  
+  return YES;
+}
+
 @end
diff --git a/ios/reactNativeApp.xcodeproj/project.pbxproj b/ios/reactNativeApp.xcodeproj/project.pbxproj
index 105c2366..5d06b264 100644
--- a/ios/reactNativeApp.xcodeproj/project.pbxproj
+++ b/ios/reactNativeApp.xcodeproj/project.pbxproj
@@ -5,6 +5,7 @@
 	};
 	objectVersion = 46;
 	objects = {
+
 /* Begin PBXBuildFile section */
 		012E4C1BA8444C8182992EEB /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B11306CBC6D24D3C990EAC4B /* Ionicons.ttf */; };
 		038BD3170181472CA3083F7C /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6603DB7CD9F34D7AB1AD5B21 /* SimpleLineIcons.ttf */; };
diff --git a/packages/localization/src/vocabularies/ManageMyBooking.js b/packages/localization/src/vocabularies/ManageMyBooking.js
index 6a9b3438..a735f8b2 100644
--- a/packages/localization/src/vocabularies/ManageMyBooking.js
+++ b/packages/localization/src/vocabularies/ManageMyBooking.js
@@ -66,12 +66,14 @@ export default {
   'mmb.passengers.title.contact_details': 'Contact details',
 
   // MMB Visa
-  'mmb.visa_state.no_visa_required': 'Visa is not required',
-  'mmb.visa_state.visa_is_required': 'Visa required in:',
+
   'mmb.passengers.visa_disclaimer':
     'Kiwi.com is not responsible for any visa issue including airport transit visas. Contact the embassy or your foreign ministry to ensure that you will be able to complete your journey. Detailed visa information is also available from the IATA Travel Centre.',
-  'mmb.visa_state.visa_may_be_required': 'Visa may be required in:',
-
+  'mmb.visa_state.no_visa_required': 'Visa is not required',
+  'mmb.visa_state.visa_is_required': 'Visa is required',
+  'mmb.visa_state.visa_is_required_in': 'Visa required in:',
+  'mmb.visa_state.visa_may_be_required_in': 'Visa may be required in:',
+  'mmb.visa_state.visa_may_be_required': 'Visa may be required',
   // MMB menu:
   'mmb.main_menu.title': 'Manage my bookings',
   'mmb.flight_services': 'Flight Services',
diff --git a/packages/relay/index.js b/packages/relay/index.js
index c1323deb..6e61c5bb 100644
--- a/packages/relay/index.js
+++ b/packages/relay/index.js
@@ -24,32 +24,29 @@ export const createFragmentContainer = (
 };
 
 export const commitMutation = (config: CommitMutationConfig) => {
-  return Relay.commitMutation(
-    PublicEnvironment.getEnvironment(() => {}),
-    config,
-  );
+  return Relay.commitMutation(PublicEnvironment.getEnvironment(), config);
 };
 
 // Flow types:
 
 type CommitMutationConfig = {|
   // please extend this type if needed
-  mutation: string,
-  variables: Object,
-  onCompleted: Function,
+  +mutation: string,
+  +variables: Object,
+  +onCompleted: Function,
 |};
 
 export type QueryRendererProps = {|
-  query: string,
-  render: (props: Object) => React.Node,
-  variables?: Object,
+  +query: string,
+  +render: (props: Object) => React.Node,
+  +variables?: Object,
 |};
 
 export type RelayPaginationProp = {|
-  hasMore: () => boolean,
-  isLoading: () => boolean,
-  loadMore: (pageSize: number, callback: (error: ?Error) => void) => void,
-  refetchConnection: (
+  +hasMore: () => boolean,
+  +isLoading: () => boolean,
+  +loadMore: (pageSize: number, callback: (error: ?Error) => void) => void,
+  +refetchConnection: (
     totalCount: number,
     callback: (error: ?Error) => void,
     refetchVariables: ?any,
@@ -57,15 +54,15 @@ export type RelayPaginationProp = {|
 |};
 
 type RefetchOptions = {|
-  force?: boolean,
+  +force?: boolean,
 |};
 
 type Disposable = {|
-  dispose(): void,
+  +dispose: () => void,
 |};
 
 export type RelayRefetchProp = {|
-  refetch: (
+  +refetch: (
     refetchVariables: Object | null | ((fragmentVariables: Object) => Object),
     renderVariables: ?Object,
     callback: ?(error: ?Error) => void,
diff --git a/packages/relay/src/Environment.js b/packages/relay/src/Environment.js
index 2e7d9353..5e5df0e7 100644
--- a/packages/relay/src/Environment.js
+++ b/packages/relay/src/Environment.js
@@ -1,41 +1,14 @@
 // @flow
 
 import { GetDeviceLocale } from '@kiwicom/mobile-localization';
-import {
-  Environment,
-  Network,
-  RecordSource,
-  Store,
-  type GraphQLResponse,
-  type ConcreteOperation,
-  type Variables,
-} from 'relay-runtime';
+import { Environment, Network, RecordSource, Store } from 'relay-runtime';
 
-type GraphQLError = {|
-  message: string,
-  locations?: {|
-    line: number,
-    column: number,
-  |},
-  path?: string[],
-  _proxy?: {|
-    statusCode: number,
-    url: string,
-  |},
+type FetcherResponse = {|
+  +data: Object,
+  +errors?: $ReadOnlyArray<Object>,
 |};
 
-// Copied from https://github.com/facebook/relay/blob/master/packages/relay-runtime/network/RelayNetworkTypes.js#L58
-type ExecutePayload = {|
-  operation: ConcreteOperation,
-  variables: Variables,
-  response: GraphQLResponse,
-  isOptimistic?: boolean,
-|};
-
-export default function createEnvironment(
-  onPartialError: GraphQLError => void,
-  accessToken: string = '',
-) {
+export default function createEnvironment(accessToken: string = '') {
   const networkHeaders: Object = {
     Accept: 'application/json',
     'Content-Type': 'application/json',
@@ -46,12 +19,9 @@ export default function createEnvironment(
     networkHeaders.authorization = accessToken;
   }
 
-  const fetchQuery = async (
-    operation,
-    variables,
-  ): Promise<{| data: Object, errors?: $ReadOnlyArray<Object> |}> => {
+  const fetchQuery = async (operation, variables): Promise<FetcherResponse> => {
     // TODO: fetch persisted queries instead (based on operation.id)
-    return await (await fetch('https://graphql.kiwi.com/', {
+    const response = await (await fetch('https://graphql.kiwi.com/', {
       method: 'POST',
       headers: networkHeaders,
       body: JSON.stringify({
@@ -59,37 +29,16 @@ export default function createEnvironment(
         variables,
       }),
     })).json();
-  };
-
-  return new PartialErrorsEnvironment(
-    {
-      network: Network.create(fetchQuery),
-      store: new Store(new RecordSource()),
-    },
-    onPartialError,
-  );
-}
 
-/**
- * This environment is workaround for: https://github.com/facebook/relay/issues/1913
- */
-export class PartialErrorsEnvironment extends Environment {
-  onPartialError: GraphQLError => void;
-
-  constructor(config: Object, onPartialError: GraphQLError => void) {
-    super(config);
-    this.onPartialError = onPartialError;
-  }
-
-  executePayload = (executePayload: ExecutePayload) => {
-    if (executePayload.response.errors) {
-      executePayload.response.errors.map(error => this.onPartialError(error));
+    if (response.errors) {
+      response.errors.forEach(error => console.warn(error));
     }
-  };
 
-  execute = (executeConfig: Object) => {
-    return super.execute(executeConfig).do({
-      next: this.executePayload,
-    });
+    return response;
   };
+
+  return new Environment({
+    network: Network.create(fetchQuery),
+    store: new Store(new RecordSource()),
+  });
 }
diff --git a/packages/relay/src/PrivateEnvironment.js b/packages/relay/src/PrivateEnvironment.js
index e7edfd97..54492c03 100644
--- a/packages/relay/src/PrivateEnvironment.js
+++ b/packages/relay/src/PrivateEnvironment.js
@@ -2,29 +2,20 @@
 
 import createEnvironment from './Environment';
 
-class PrivateEnvironment {
+export default new class PrivateEnvironment {
   environment = null;
   token = null;
-  currentPartialErrorHandler: Object => void;
 
-  partialErrorHandler = (error: Object) => {
-    this.currentPartialErrorHandler(error);
-  };
-
-  getEnvironment = (partialErrorHandler: Object => void, token: string) => {
+  getEnvironment = (token: string) => {
     if (!token) {
       throw new Error('Cannot create private environment without token.');
     }
 
     if (this.environment === null || token !== this.token) {
-      this.environment = createEnvironment(this.partialErrorHandler, token);
+      this.environment = createEnvironment(token);
     }
 
     this.token = token;
-    this.currentPartialErrorHandler = partialErrorHandler;
     return this.environment;
   };
-}
-
-const privateEnvironment = new PrivateEnvironment();
-export default privateEnvironment;
+}();
diff --git a/packages/relay/src/PublicEnvironment.js b/packages/relay/src/PublicEnvironment.js
index 1479d5c2..21d56670 100644
--- a/packages/relay/src/PublicEnvironment.js
+++ b/packages/relay/src/PublicEnvironment.js
@@ -2,23 +2,14 @@
 
 import createEnvironment from './Environment';
 
-class PublicEnvironment {
+export default new class PublicEnvironment {
   environment = null;
-  currentPartialErrorHandler: Object => void;
 
   constructor() {
-    this.environment = createEnvironment(this.partialErrorHandler, '');
+    this.environment = createEnvironment();
   }
 
-  partialErrorHandler = (error: Object) => {
-    this.currentPartialErrorHandler(error);
-  };
-
-  getEnvironment = (partialErrorHandler: Object => void) => {
-    this.currentPartialErrorHandler = partialErrorHandler;
+  getEnvironment = () => {
     return this.environment;
   };
-}
-
-const publicEnvironment = new PublicEnvironment();
-export default publicEnvironment;
+}();
diff --git a/packages/relay/src/QueryRenderer.js b/packages/relay/src/QueryRenderer.js
index 88a7f57e..d76f9d5d 100644
--- a/packages/relay/src/QueryRenderer.js
+++ b/packages/relay/src/QueryRenderer.js
@@ -2,11 +2,7 @@
 
 import * as React from 'react';
 import { QueryRenderer as OriginalQueryRenderer } from '@kiwicom/mobile-relay';
-import {
-  FullPageLoading,
-  GeneralError,
-  PartialFailure,
-} from '@kiwicom/mobile-shared';
+import { FullPageLoading, GeneralError } from '@kiwicom/mobile-shared';
 import { Translation } from '@kiwicom/mobile-localization';
 
 import PublicEnvironment from './PublicEnvironment';
@@ -15,34 +11,24 @@ import type { QueryRendererProps } from '../index';
 
 type Props = {|
   ...QueryRendererProps,
-  accessToken?: string,
+  +accessToken?: string,
 |};
 
-export default class QueryRenderer extends React.Component<Props> {
-  partialError: Object;
+type RendererResponse = {|
+  +error?: Object,
+  +props?: Object,
+|};
 
+export default class QueryRenderer extends React.Component<Props> {
   createEnvironment = () => {
     if (!this.props.accessToken) {
-      return PublicEnvironment.getEnvironment(this.partialErrorHandler);
+      return PublicEnvironment.getEnvironment();
     }
 
-    return PrivateEnvironment.getEnvironment(
-      this.partialErrorHandler,
-      this.props.accessToken || '',
-    );
-  };
-
-  partialErrorHandler = (partialError: Object) => {
-    this.partialError = partialError;
+    return PrivateEnvironment.getEnvironment(this.props.accessToken || '');
   };
 
-  renderRelayContainer = ({
-    error,
-    props,
-  }: {
-    error?: Object,
-    props?: Object,
-  }) => {
+  renderRelayContainer = ({ error, props }: RendererResponse) => {
     if (error) {
       if (error.message === 'Network request failed') {
         // See: https://github.com/github/fetch/blob/fcc4e1b48cfb5a2b1625fcd6eac06d954b00ccb6/fetch.js#L438-L444
@@ -64,16 +50,6 @@ export default class QueryRenderer extends React.Component<Props> {
     }
 
     if (props) {
-      if (this.partialError) {
-        // partial failure (data != null, errors != null)
-        // Relay swallows all GraphQL errors if 'data != null' (see: https://github.com/facebook/relay/issues/1913)
-
-        console.log('QueryRenderer partial error:'); // eslint-disable-line no-console
-        console.log(JSON.stringify(this.partialError, null, 2)); // eslint-disable-line no-console
-
-        return <PartialFailure>{this.props.render(props)}</PartialFailure>;
-      }
-
       // success (data != null, errors == null)
       return this.props.render(props);
     }
diff --git a/packages/shared/index.js b/packages/shared/index.js
index 15802144..83595956 100644
--- a/packages/shared/index.js
+++ b/packages/shared/index.js
@@ -59,7 +59,6 @@ export { default as WebView } from './src/WebView';
 export { default as SimpleCard } from './src/SimpleCard';
 
 export { default as GeneralError } from './src/errors/GeneralError';
-export { default as PartialFailure } from './src/errors/PartialFailure';
 
 export { default as ReadMore } from './src/ReadMore';
 export { default as BottomSheet } from './src/BottomSheet';
diff --git a/packages/shared/src/HeaderRightButton.js b/packages/shared/src/HeaderRightButton.js
index 89e9ec98..d85537e0 100644
--- a/packages/shared/src/HeaderRightButton.js
+++ b/packages/shared/src/HeaderRightButton.js
@@ -3,15 +3,13 @@
 import * as React from 'react';
 import { View } from 'react-native';
 
-import Color from './Color';
 import StyleSheet from './PlatformStyleSheet';
 import Touchable from './Touchable';
-import Icon from './icons/Icon';
 
 type Props = {|
-  onPress: () => void,
-  tintColor?: string,
-  onLongPress?: (React.ElementRef<typeof Touchable>) => void,
+  +onPress: () => void,
+  +onLongPress?: (React.ElementRef<typeof Touchable>) => void,
+  +children?: React.Node,
 |};
 
 type State = {|
@@ -26,10 +24,6 @@ export default class HeaderRightButton extends React.PureComponent<
     reference: null,
   };
 
-  static defaultProps = {
-    tintColor: Color.brand,
-  };
-
   storeReference = (reference: React.ElementRef<typeof Touchable> | null) => {
     this.setState({ reference });
   };
@@ -41,7 +35,7 @@ export default class HeaderRightButton extends React.PureComponent<
   };
 
   render = () => {
-    const { onPress, tintColor } = this.props;
+    const { onPress } = this.props;
 
     return (
       <Touchable
@@ -55,7 +49,7 @@ export default class HeaderRightButton extends React.PureComponent<
         ref={this.storeReference}
       >
         <View style={styles.container}>
-          <Icon style={styles.icon} name="map" size={24} color={tintColor} />
+          <View style={styles.innerContainer}>{this.props.children}</View>
         </View>
       </Touchable>
     );
@@ -68,7 +62,7 @@ const styles = StyleSheet.create({
     flexDirection: 'row',
     backgroundColor: 'transparent',
   },
-  icon: {
+  innerContainer: {
     ios: {
       marginStart: 22,
       marginEnd: 10,
diff --git a/packages/shared/src/errors/PartialFailure.js b/packages/shared/src/errors/PartialFailure.js
deleted file mode 100644
index 8661352a..00000000
--- a/packages/shared/src/errors/PartialFailure.js
+++ /dev/null
@@ -1,91 +0,0 @@
-// @flow
-
-import * as React from 'react';
-import { View } from 'react-native';
-import { Touchable } from '@kiwicom/mobile-shared';
-import { Translation } from '@kiwicom/mobile-localization';
-
-import StyleSheet from '../PlatformStyleSheet';
-import Color from '../Color';
-import Icon from '../icons/Icon';
-
-type Props = {|
-  children: React.Node,
-|};
-
-type State = {|
-  dismissed: boolean,
-|};
-
-export default class PartialFailure extends React.Component<Props, State> {
-  state = {
-    dismissed: false,
-  };
-
-  toggle = () => {
-    this.setState(({ dismissed }) => ({
-      dismissed: !dismissed,
-    }));
-  };
-
-  render() {
-    const { children } = this.props;
-
-    if (this.state.dismissed === true) {
-      return (
-        <React.Fragment>
-          {children}
-          <Touchable
-            style={style.dismissed}
-            accessibilityLabel="Show warning"
-            onPress={this.toggle}
-          >
-            <Icon name="warning" size={20} />
-          </Touchable>,
-        </React.Fragment>
-      );
-    } else {
-      return (
-        <React.Fragment>
-          {children}
-          <View style={style.container}>
-            <View style={style.message}>
-              <Translation id="partial_failure.error" />
-            </View>
-            <Touchable accessibilityLabel="Hide warning" onPress={this.toggle}>
-              <Icon name="close" size={20} />
-            </Touchable>
-          </View>
-        </React.Fragment>
-      );
-    }
-  }
-}
-
-const style = StyleSheet.create({
-  container: {
-    flexDirection: 'row',
-    flex: 1,
-    alignItems: 'center',
-    position: 'absolute',
-    start: 0,
-    end: 0,
-    bottom: 0,
-    backgroundColor: Color.red.light,
-    paddingVertical: 5,
-    paddingHorizontal: 10,
-  },
-  message: {
-    flex: 1,
-    justifyContent: 'center',
-    alignItems: 'center',
-  },
-  dismissed: {
-    position: 'absolute',
-    end: 0,
-    bottom: 0,
-    backgroundColor: Color.red.light,
-    padding: 5,
-    borderTopStartRadius: 5,
-  },
-});
diff --git a/schema.graphql b/schema.graphql
index a7385b3d..1e690736 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -149,6 +149,7 @@ type Booking {
   bookedServices: [BookedService]
   contactDetails: BookingContactDetails
   isPastBooking: Boolean
+  availableWhitelabeledServices: WhitelabeledServices
   oneWay: BookingOneWay
   return: BookingReturn
   multicity: BookingMulticity
@@ -232,6 +233,7 @@ interface BookingInterface {
   bookedServices: [BookedService]
   contactDetails: BookingContactDetails
   isPastBooking: Boolean
+  availableWhitelabeledServices: WhitelabeledServices
 }
 
 type BookingMulticity implements BookingInterface {
@@ -266,6 +268,7 @@ type BookingMulticity implements BookingInterface {
   bookedServices: [BookedService]
   contactDetails: BookingContactDetails
   isPastBooking: Boolean
+  availableWhitelabeledServices: WhitelabeledServices
 
   """Initial origin."""
   start: RouteStop
@@ -312,6 +315,7 @@ type BookingOneWay implements BookingInterface {
   bookedServices: [BookedService]
   contactDetails: BookingContactDetails
   isPastBooking: Boolean
+  availableWhitelabeledServices: WhitelabeledServices
   trip: Trip
 }
 
@@ -348,6 +352,7 @@ type BookingReturn implements BookingInterface {
   bookedServices: [BookedService]
   contactDetails: BookingContactDetails
   isPastBooking: Boolean
+  availableWhitelabeledServices: WhitelabeledServices
 
   """Trip from origin to destination."""
   outbound: Trip
@@ -684,6 +689,65 @@ input DurationInput {
   maxFlightDuration: Int
 }
 
+"""Combination of flight and hotel"""
+type DynamicPackage {
+  """The ID of an object"""
+  id: ID!
+
+  """Accommodation part of the package"""
+  hotel: Hotel
+
+  """Transport part of the package"""
+  flight: Flight
+
+  """
+  URL to the whitelabel page where this dynamic package can be purchased
+  """
+  whitelabelUrl: String
+
+  """Total price"""
+  price: Price
+}
+
+"""A connection to a list of items."""
+type DynamicPackageConnection {
+  """Information to aid in pagination."""
+  pageInfo: PageInfo!
+
+  """A list of edges."""
+  edges: [DynamicPackageEdge]
+}
+
+"""An edge in a connection."""
+type DynamicPackageEdge {
+  """The item at the end of the edge"""
+  node: DynamicPackage
+
+  """A cursor for use in pagination"""
+  cursor: String!
+}
+
+input DynamicPackagesSimpleSearchInput {
+  """Valid airport code according the IATA standard"""
+  fromAirport: String!
+
+  """Valid airport code according the IATA standard"""
+  toAirport: String!
+
+  """List of outbound flight numbers (e.g. OK123)"""
+  outboundFlights: [String!]!
+
+  """List of inbound flight numbers (e.g. OK123)"""
+  inboundFlights: [String!]!
+
+  """Departure date"""
+  date: Date!
+
+  """Return date"""
+  returnDate: Date!
+  passengers: PassengersInput!
+}
+
 type FAQArticle {
   """The ID of an object"""
   id: ID!
@@ -1438,6 +1502,15 @@ enum LocationType {
   subdivision
 }
 
+type LoungeService {
+  relevantAirports: [LoungeServiceRelevantAirports]
+}
+
+type LoungeServiceRelevantAirports {
+  whitelabelURL: String
+  location: Location
+}
+
 """An object with an ID"""
 interface Node {
   """The id of the object."""
@@ -1459,6 +1532,10 @@ type PageInfo {
   endCursor: String
 }
 
+type ParkingService {
+  whitelabelURL: String
+}
+
 """The passengers associated with the booking"""
 type Passenger {
   databaseId: Int
@@ -1477,6 +1554,7 @@ type Passenger {
 
 input PassengersInput {
   adults: Int!
+  infants: Int
 }
 
 type Price {
@@ -1695,6 +1773,22 @@ type RootQuery {
     """Language in which the text of the article is returned."""
     language: Language
   ): FAQArticle
+
+  """
+  All dynamic packages. Dynamic package is a combination of return flight and
+  accommodation in hotel. It saves time and also the price should be better then
+  buying flight and acommodation separately.
+  """
+  allDynamicPackages(
+    simpleSearch: DynamicPackagesSimpleSearchInput!
+
+    """An ISO-4217 currency code."""
+    currency: Currency
+    after: String
+    first: Int
+    before: String
+    last: Int
+  ): DynamicPackageConnection
 }
 
 type RouteStop {
@@ -1753,3 +1847,8 @@ type Visa {
   """Countries where visa is not required"""
   okIn: [Location]
 }
+
+type WhitelabeledServices {
+  lounge(departureTime: DateTime!): LoungeService
+  parking(fromDate: DateTime!, toDate: DateTime!): ParkingService
+}


Test patch:
diff --git a/app/MMB/src/context/__tests__/BookingDetailContext.test.js b/app/MMB/src/context/__tests__/BookingDetailContext.test.js
index 09ed9480..cb8d960e 100644
--- a/app/MMB/src/context/__tests__/BookingDetailContext.test.js
+++ b/app/MMB/src/context/__tests__/BookingDetailContext.test.js
@@ -2,6 +2,7 @@
 
 import * as React from 'react';
 import renderer from 'react-test-renderer';
+import { DateFormatter } from '@kiwicom/mobile-localization';
 
 import BookingDetailContext from '../BookingDetailContext';
 
@@ -9,23 +10,45 @@ class ContextConsumer extends React.Component<{}> {
   render = () => null;
 }
 
+const getWrapper = () =>
+  renderer.create(
+    <BookingDetailContext.Provider>
+      <BookingDetailContext.Consumer>
+        {({ actions: { setBookingDetail }, ...rest }) => (
+          <ContextConsumer {...rest} setBookingDetail={setBookingDetail} />
+        )}
+      </BookingDetailContext.Consumer>
+    </BookingDetailContext.Provider>,
+  );
+
 describe('BookingDetailContext', () => {
   it('injects the props to consumers', () => {
-    const wrapper = renderer.create(
-      <BookingDetailContext.Provider isPastBooking={false} bookingId="1234">
-        <BookingDetailContext.Consumer>
-          {({ isPastBooking, bookingId }) => (
-            <ContextConsumer
-              isPastBooking={isPastBooking}
-              bookingId={bookingId}
-            />
-          )}
-        </BookingDetailContext.Consumer>
-      </BookingDetailContext.Provider>,
-    );
+    const wrapper = getWrapper();
 
     const instance = wrapper.root.findByType(ContextConsumer);
     expect(instance.props.isPastBooking).toBe(false);
-    expect(instance.props.bookingId).toBe('1234');
+    expect(instance.props.bookingId).toBe('');
+    expect(
+      DateFormatter(instance.props.arrivalTime).formatForMachine(),
+    ).toEqual(DateFormatter(new Date()).formatForMachine());
+    expect(instance.props.arrivalCityId).toBe('');
+    expect(typeof instance.props.setBookingDetail).toBe('function');
+  });
+
+  it('it setsBookingDetail', () => {
+    const wrapper = getWrapper();
+    const instance = wrapper.root.findByType(ContextConsumer);
+
+    instance.props.setBookingDetail({
+      isPastBooking: true,
+      bookingId: '123',
+      arrivalCityId: 'oslo_no',
+      arrivalTime: new Date(1),
+    });
+
+    expect(instance.props.isPastBooking).toBe(true);
+    expect(instance.props.bookingId).toBe('123');
+    expect(instance.props.arrivalCityId).toBe('oslo_no');
+    expect(instance.props.arrivalTime).toEqual(new Date(1));
   });
 });
diff --git a/app/MMB/src/scenes/passenger/__tests__/__snapshots__/Passenger.test.js.snap b/app/MMB/src/scenes/passenger/__tests__/__snapshots__/Passenger.test.js.snap
index 47399967..6bf7fd63 100644
--- a/app/MMB/src/scenes/passenger/__tests__/__snapshots__/Passenger.test.js.snap
+++ b/app/MMB/src/scenes/passenger/__tests__/__snapshots__/Passenger.test.js.snap
@@ -73,20 +73,17 @@ exports[`renders 1`] = `
         }
       />
     </Row>
-    <Relay(VisaInformationWithContext)
-      visa={
-        Object {
-          "birthday": "1984-05-10T00:00:00.000Z",
-          "fullName": "Trond Bergquist",
-          "insuranceType": "TRAVEL_PLUS",
-          "nationality": "no",
-          "title": "Mr",
-          "travelDocument": Object {
-            "idNumber": "123456",
-          },
-        }
-      }
-    />
+    <VisaInformationWithContext
+      requiredIn={Array []}
+      warningIn={Array []}
+    >
+      <VisaRequired
+        countries={Array []}
+      />
+      <VisaWarning
+        countries={Array []}
+      />
+    </VisaInformationWithContext>
   </MenuGroup>
 </SimpleCard>
 `;
diff --git a/app/MMB/src/scenes/passenger/visa/__tests__/VisaInformation.test.js b/app/MMB/src/scenes/passenger/visa/__tests__/VisaInformation.test.js
index a697905a..4500af24 100644
--- a/app/MMB/src/scenes/passenger/visa/__tests__/VisaInformation.test.js
+++ b/app/MMB/src/scenes/passenger/visa/__tests__/VisaInformation.test.js
@@ -9,13 +9,9 @@ import VisaRequired from '../VisaRequired';
 import VisaWarning from '../VisaWarning';
 
 const defaultProps = {
-  visa: {
-    visaInformation: {
-      requiredIn: [],
-      warningIn: [],
-    },
-    isPastBooking: false,
-  },
+  requiredIn: [],
+  warningIn: [],
+  isPastBooking: false,
 };
 
 describe('VisaInformation', () => {
@@ -24,15 +20,20 @@ describe('VisaInformation', () => {
       ...defaultProps,
       isPastBooking: true,
     };
-    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
-    const wrapper = renderer.create(<VisaInformation {...props} />);
+    const wrapper = renderer.create(
+      <VisaInformation {...props}>{false}</VisaInformation>,
+    );
 
     expect(wrapper.toTree().rendered).toBe(null);
   });
 
   it('renders visa ok when requiredIn and warningIn contains no elements', () => {
-    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
-    const wrapper = renderer.create(<VisaInformation {...defaultProps} />);
+    const wrapper = renderer.create(
+      <VisaInformation {...defaultProps}>
+        <VisaRequired countries={[]} />
+        <VisaWarning countries={[]} />
+      </VisaInformation>,
+    );
 
     expect(wrapper.root.findByType(VisaOk)).toBeDefined();
     expect(() => {
@@ -46,15 +47,16 @@ describe('VisaInformation', () => {
   it('renders visa warning and visa required when they contain elements', () => {
     const props = {
       ...defaultProps,
-      visa: {
-        visaInformation: {
-          requiredIn: [{ name: 'Norway' }],
-          warningIn: [{ name: 'Sweden' }],
-        },
-      },
+      requiredIn: ['Norway'],
+      warningIn: ['Norway'],
     };
-    // $FlowRelayIssue: https://github.com/facebook/relay/issues/2394
-    const wrapper = renderer.create(<VisaInformation {...props} />);
+
+    const wrapper = renderer.create(
+      <VisaInformation {...props}>
+        <VisaRequired countries={['Norway']} />
+        <VisaWarning countries={['Norway']} />
+      </VisaInformation>,
+    );
 
     expect(wrapper.root.findByType(VisaRequired)).toBeDefined();
     expect(wrapper.root.findByType(VisaWarning)).toBeDefined();
diff --git a/app/MMB/src/scenes/passenger/visa/__tests__/__snapshots__/VisaRequired.test.js.snap b/app/MMB/src/scenes/passenger/visa/__tests__/__snapshots__/VisaRequired.test.js.snap
index 456c5da3..aa44180a 100644
--- a/app/MMB/src/scenes/passenger/visa/__tests__/__snapshots__/VisaRequired.test.js.snap
+++ b/app/MMB/src/scenes/passenger/visa/__tests__/__snapshots__/VisaRequired.test.js.snap
@@ -6,7 +6,7 @@ exports[`VisaRequired renders with one country in the array 1`] = `
 <Alert
   title={
     <Translation
-      id="mmb.visa_state.visa_is_required"
+      id="mmb.visa_state.visa_is_required_in"
     />
   }
   type="danger"
@@ -31,7 +31,7 @@ exports[`VisaRequired renders with several countries in the array 1`] = `
 <Alert
   title={
     <Translation
-      id="mmb.visa_state.visa_is_required"
+      id="mmb.visa_state.visa_is_required_in"
     />
   }
   type="danger"
diff --git a/packages/relay/src/__tests__/Environment.test.js b/packages/relay/src/__tests__/Environment.test.js
deleted file mode 100644
index 64b99044..00000000
--- a/packages/relay/src/__tests__/Environment.test.js
+++ /dev/null
@@ -1,43 +0,0 @@
-// @flow
-
-import { PartialErrorsEnvironment } from '../Environment';
-
-const getEnvironment = (onPartialError: Function) => {
-  return new PartialErrorsEnvironment(
-    {
-      network: jest.fn(),
-      store: jest.fn(),
-    },
-    onPartialError,
-  );
-};
-
-describe('PartialErrorsEnvironment', () => {
-  it('calls onPartialError when error is present', () => {
-    const onPartialError = jest.fn();
-    const environment = getEnvironment(onPartialError);
-    environment.executePayload({
-      response: {
-        errors: [1, 2],
-      },
-      operation: null,
-      variables: null,
-    });
-
-    expect(onPartialError).toHaveBeenCalledWith(1);
-    expect(onPartialError).toHaveBeenCalledWith(2);
-  });
-  it('does not call onPartialError when error is present', () => {
-    const onPartialError = jest.fn();
-    const environment = getEnvironment(onPartialError);
-    environment.executePayload({
-      response: {
-        errors: null,
-      },
-      operation: null,
-      variables: null,
-    });
-
-    expect(onPartialError).not.toHaveBeenCalled();
-  });
-});
diff --git a/packages/relay/src/__tests__/PrivateEnvironment.test.js b/packages/relay/src/__tests__/PrivateEnvironment.test.js
index 638b87b2..ef4a1288 100644
--- a/packages/relay/src/__tests__/PrivateEnvironment.test.js
+++ b/packages/relay/src/__tests__/PrivateEnvironment.test.js
@@ -11,13 +11,9 @@ createEnvironment.mockImplementation(() => {
   return `environment ${++count}`;
 });
 
-let currentPartialErrorHandlerIntial =
-  PrivateEnvironment.currentPartialErrorHandler;
-
 afterEach(() => {
   PrivateEnvironment.environment = null;
   PrivateEnvironment.token = null;
-  PrivateEnvironment.currentPartialErrorHandler = currentPartialErrorHandlerIntial;
   count = 0;
 });
 
@@ -25,79 +21,52 @@ describe('PrivateEnvironment', () => {
   it('should be initiated without values', () => {
     expect(PrivateEnvironment.environment).toBe(null);
     expect(PrivateEnvironment.token).toBe(null);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toBeUndefined();
     expect(createEnvironment).not.toHaveBeenCalled();
   });
 
   it('should throw an error if token is undefined, null or empty string', () => {
-    const errorHandler = jest.fn();
-    let token1;
-    const token2 = null;
-    const token3 = '';
-
     expect(() => {
-      PrivateEnvironment.getEnvironment(errorHandler, token1);
+      // $FlowExpectedError: Intentionally testing what happens if undefined is passed
+      PrivateEnvironment.getEnvironment(undefined);
     }).toThrowError('Cannot create private environment without token.');
 
     expect(() => {
       // $FlowExpectedError: Intentionally testing what happens if null is passed
-      PrivateEnvironment.getEnvironment(errorHandler, token2);
+      PrivateEnvironment.getEnvironment(null);
     }).toThrowError('Cannot create private environment without token.');
 
     expect(() => {
-      PrivateEnvironment.getEnvironment(errorHandler, token3);
+      PrivateEnvironment.getEnvironment('');
     }).toThrowError('Cannot create private environment without token.');
 
     expect(createEnvironment).not.toHaveBeenCalled();
   });
 
   it('creates a new environment if one does not exist', () => {
-    const errorHandler = jest.fn();
-    const token = 'myToken';
-
-    PrivateEnvironment.getEnvironment(errorHandler, token);
+    PrivateEnvironment.getEnvironment('myToken');
     expect(PrivateEnvironment.environment).toEqual('environment 1');
-    expect(PrivateEnvironment.token).toEqual(token);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
+    expect(PrivateEnvironment.token).toEqual('myToken');
   });
 
   it('creates a new environment if token changes', () => {
-    const errorHandler = jest.fn();
-    const token = 'myToken';
-    const newToken = 'newToken';
-
-    PrivateEnvironment.getEnvironment(errorHandler, token);
+    PrivateEnvironment.getEnvironment('myToken');
     expect(PrivateEnvironment.environment).toEqual('environment 1');
-    expect(PrivateEnvironment.token).toEqual(token);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
+    expect(PrivateEnvironment.token).toEqual('myToken');
 
-    PrivateEnvironment.getEnvironment(errorHandler, newToken);
+    PrivateEnvironment.getEnvironment('newToken');
     expect(PrivateEnvironment.environment).toEqual('environment 2');
-    expect(PrivateEnvironment.token).toEqual(newToken);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
+    expect(PrivateEnvironment.token).toEqual('newToken');
   });
 
   it('does not create a new environment if token is the same', () => {
-    const errorHandler = jest.fn();
-    const token = 'myToken';
-
-    PrivateEnvironment.getEnvironment(errorHandler, token);
+    const e1 = PrivateEnvironment.getEnvironment('myToken');
     expect(PrivateEnvironment.environment).toEqual('environment 1');
-    expect(PrivateEnvironment.token).toEqual(token);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
+    expect(PrivateEnvironment.token).toEqual('myToken');
 
-    PrivateEnvironment.getEnvironment(errorHandler, token);
+    const e2 = PrivateEnvironment.getEnvironment('myToken');
     expect(PrivateEnvironment.environment).toEqual('environment 1');
-    expect(PrivateEnvironment.token).toEqual(token);
-    expect(PrivateEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
-  });
-
-  it('calls error handler on partial error', () => {
-    const errorHandler = jest.fn();
-    const token = 'myToken';
+    expect(PrivateEnvironment.token).toEqual('myToken');
 
-    PrivateEnvironment.getEnvironment(errorHandler, token);
-    PrivateEnvironment.partialErrorHandler({ error: 'error' });
-    expect(errorHandler).toBeCalledWith({ error: 'error' });
+    expect(e1).toBe(e2);
   });
 });
diff --git a/packages/relay/src/__tests__/PublicEnvironment.test.js b/packages/relay/src/__tests__/PublicEnvironment.test.js
index 770b5641..64a4f08c 100644
--- a/packages/relay/src/__tests__/PublicEnvironment.test.js
+++ b/packages/relay/src/__tests__/PublicEnvironment.test.js
@@ -11,18 +11,9 @@ describe('PublicEnvironment', () => {
     expect(PublicEnvironment.environment).toEqual('environment');
   });
 
-  it('should set a partial error handler', () => {
-    const errorHandler = jest.fn();
-
-    PublicEnvironment.getEnvironment(errorHandler);
-    expect(PublicEnvironment.currentPartialErrorHandler).toEqual(errorHandler);
-  });
-
-  it('should call the partial error handler on partial error', () => {
-    const errorHandler = jest.fn();
-
-    PublicEnvironment.getEnvironment(errorHandler);
-    PublicEnvironment.partialErrorHandler({ error: 'error' });
-    expect(errorHandler).toBeCalledWith({ error: 'error' });
+  it('should return the same environment instances', () => {
+    expect(PublicEnvironment.getEnvironment()).toBe(
+      PublicEnvironment.getEnvironment(),
+    );
   });
 });
diff --git a/packages/shared/src/errors/__tests__/PartialFailure.test.js b/packages/shared/src/errors/__tests__/PartialFailure.test.js
deleted file mode 100644
index e3496ba8..00000000
--- a/packages/shared/src/errors/__tests__/PartialFailure.test.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// @flow
-
-import * as React from 'react';
-import renderer from 'react-test-renderer';
-import { Translation } from '@kiwicom/mobile-localization';
-
-import PartialFailure from '../PartialFailure';
-
-it('renders failure and its children', () => {
-  expect(
-    renderer.create(
-      <PartialFailure>
-        <Translation passThrough="Some content" />
-      </PartialFailure>,
-    ),
-  ).toMatchSnapshot();
-});
diff --git a/packages/shared/src/errors/__tests__/__snapshots__/PartialFailure.test.js.snap b/packages/shared/src/errors/__tests__/__snapshots__/PartialFailure.test.js.snap
deleted file mode 100644
index ed66a648..00000000
--- a/packages/shared/src/errors/__tests__/__snapshots__/PartialFailure.test.js.snap
+++ /dev/null
@@ -1,107 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders failure and its children 1`] = `
-Array [
-  <Text
-    accessible={true}
-    allowFontScaling={true}
-    ellipsizeMode="tail"
-    style={
-      Array [
-        Object {
-          "color": "#171b1e",
-          "fontSize": 14,
-          "fontWeight": "normal",
-          "letterSpacing": -0.15,
-        },
-        undefined,
-      ]
-    }
-  >
-    Some content
-  </Text>,
-  <View
-    style={
-      Object {
-        "alignItems": "center",
-        "backgroundColor": "#fae8e8",
-        "bottom": 0,
-        "end": 0,
-        "flex": 1,
-        "flexDirection": "row",
-        "paddingHorizontal": 10,
-        "paddingVertical": 5,
-        "position": "absolute",
-        "start": 0,
-      }
-    }
-  >
-    <View
-      style={
-        Object {
-          "alignItems": "center",
-          "flex": 1,
-          "justifyContent": "center",
-        }
-      }
-    >
-      <Text
-        accessible={true}
-        allowFontScaling={true}
-        ellipsizeMode="tail"
-        style={
-          Array [
-            Object {
-              "color": "#171b1e",
-              "fontSize": 14,
-              "fontWeight": "normal",
-              "letterSpacing": -0.15,
-            },
-            undefined,
-          ]
-        }
-      >
-        
-      </Text>
-    </View>
-    <View
-      accessibilityLabel="Hide warning"
-      accessible={true}
-      isTVSelectable={true}
-      onResponderGrant={[Function]}
-      onResponderMove={[Function]}
-      onResponderRelease={[Function]}
-      onResponderTerminate={[Function]}
-      onResponderTerminationRequest={[Function]}
-      onStartShouldSetResponder={[Function]}
-      style={
-        Object {
-          "opacity": 1,
-        }
-      }
-    >
-      <Text
-        accessible={true}
-        allowFontScaling={false}
-        ellipsizeMode="tail"
-        style={
-          Array [
-            Object {
-              "color": "#7f91a8",
-              "fontSize": 20,
-            },
-            undefined,
-            Object {
-              "fontFamily": "Material Icons",
-              "fontStyle": "normal",
-              "fontWeight": "normal",
-            },
-          ]
-        }
-      >
-        
-      </Text>
-    </View>
-  </View>,
-]
-`;