Repository: kiwicom/mobile
Pull request #918 (2018-07-25 07:05:41)

MMB: Prepare data for apple wallet screen
I considered two approaches to get data for the apple wallet screen. 

A: Use query renderer
• I would have to pass legId and passengerId the new screen
• Query the booking for all legs, loop all legs to find my leg, loop pkpasses to find my passenger
• This does not sound optimal

B: The chosen approach. 
• Prepare data in context and set the selected one when clicking on the passenger
• I would then be able to get all needed data on the apple wallet screen from the context through the selectedSegment. 
• I do have to prop drill legId down to the click handler, but I would have had to do that with approach A also. 

C: Could be an approach I did not consider, so please let me know if you see another way 😄 

RobinCsl: Well, interestingly, this is the same kind of problem I am dealing with at the moment: how to pass data correctly when navigating from one screen to another when this deals with one item of a list... 
I think the approach with the context is quite good because it really is about the context and all the information is managed by one state store. 
If we had had some global store, then it could have been slightly easier as we would just need to connect to that store and all the information would be available. I guess people are using the Relay Store as a replacement for Redux. SO maybe it would be possible to do something similar? My 2 cents.

One further comment, more specific to the code: it does not look like you are using `selectedSegment` anywhere yet. Is it by design and will be used later?
tbergq: >  Is it by design and will be used later

Yes, when I navigate to `AppleWalletScreen` I will use the `selectedSegment` that way, I don't need to pass any parameters, or do any queries on that screen. 
tbergq: @RobinCsl 🚀 

Patch:
diff --git a/app/MMB/index.js b/app/MMB/index.js
index 0a03d4fb..a9940806 100644
--- a/app/MMB/index.js
+++ b/app/MMB/index.js
@@ -11,6 +11,7 @@ import {
 
 import NavigationStack from './src/navigation/NavigationStack';
 import BookingDetailContext from './src/context/BookingDetailContext';
+import WalletContext from './src/context/WalletContext';
 
 type Props = {|
   currency: string,
@@ -23,11 +24,13 @@ class ManageMyBookingPackage extends React.Component<Props> {
   render = () => (
     <Dimensions.Provider dimensions={this.props.dimensions}>
       <AuthContext.Provider accessToken={this.props.accessToken}>
-        <BookingDetailContext.Provider>
-          <NavigationStack
-            onNavigationStateChange={this.props.onNavigationStateChange}
-          />
-        </BookingDetailContext.Provider>
+        <WalletContext.Provider>
+          <BookingDetailContext.Provider>
+            <NavigationStack
+              onNavigationStateChange={this.props.onNavigationStateChange}
+            />
+          </BookingDetailContext.Provider>
+        </WalletContext.Provider>
       </AuthContext.Provider>
     </Dimensions.Provider>
   );
diff --git a/app/MMB/src/context/WalletContext.js b/app/MMB/src/context/WalletContext.js
new file mode 100644
index 00000000..f29a03d7
--- /dev/null
+++ b/app/MMB/src/context/WalletContext.js
@@ -0,0 +1,103 @@
+// @flow strict
+
+import * as React from 'react';
+
+const defaultState = {
+  segments: [],
+  selectedSegment: null,
+  actions: {
+    addSegment: () => {},
+    addPkpassData: () => {},
+    setSelectedSegment: () => {},
+  },
+};
+const { Consumer, Provider: ContextProvider } = React.createContext({
+  ...defaultState,
+});
+
+type Props = {|
+  +children: React.Node,
+|};
+
+export type Segment = {|
+  +id: string,
+  +airlineLogoUrl: string,
+  +flightDate: Date | null,
+  +passengerName?: string,
+  +pkpassUrl?: string,
+|};
+
+type State = {|
+  segments: $ReadOnlyArray<Segment>,
+  selectedSegment: Segment | null,
+  +actions: {|
+    +addSegment: (segment: Segment) => void,
+    +setSelectedSegment: (segmentId: string | null) => void,
+    +addPkpassData: (
+      passengerName: string,
+      pkpassUrl: string,
+      segmentId: string,
+    ) => void,
+  |},
+|};
+
+class Provider extends React.Component<Props, State> {
+  constructor(props: Props) {
+    super(props);
+
+    this.state = {
+      segments: [],
+      selectedSegment: null,
+      actions: {
+        addSegment: this.addSegment,
+        addPkpassData: this.addPkpassData,
+        setSelectedSegment: this.setSelectedSegment,
+      },
+    };
+  }
+
+  addSegment = (segment: Segment) => {
+    this.setState(state => ({
+      segments: [...state.segments, segment],
+    }));
+  };
+
+  addPkpassData = (
+    passengerName: string,
+    pkpassUrl: string,
+    segmentId: string,
+  ) => {
+    this.setState(
+      state => ({
+        segments: state.segments.map(segment => {
+          if (segment.id === segmentId) {
+            return {
+              ...segment,
+              passengerName,
+              pkpassUrl,
+            };
+          }
+          return segment;
+        }),
+      }),
+      () => {
+        this.setSelectedSegment(segmentId);
+      },
+    );
+  };
+
+  setSelectedSegment = (segmentId: string | null) => {
+    this.setState(state => ({
+      selectedSegment:
+        segmentId === null
+          ? null
+          : state.segments.find(segment => segment.id === segmentId),
+    }));
+  };
+
+  render = () => (
+    <ContextProvider value={this.state}>{this.props.children}</ContextProvider>
+  );
+}
+
+export default { Consumer, Provider };
diff --git a/app/MMB/src/navigation/AppleWalletScreen.js b/app/MMB/src/navigation/AppleWalletScreen.js
index 7ad1423d..3977f3e8 100644
--- a/app/MMB/src/navigation/AppleWalletScreen.js
+++ b/app/MMB/src/navigation/AppleWalletScreen.js
@@ -5,22 +5,41 @@ import { View } from 'react-native';
 import { StyleSheet, Color } from '@kiwicom/mobile-shared';
 
 import AppleWalletScene from '../scenes/appleWallet/AppleWalletScene';
+import WalletContext from '../context/WalletContext';
 
-export default function AppleWalletScreen() {
-  return (
+type PropsWithContext = {|
+  +setSelectedSegment: (segmentId: string | null) => void,
+|};
+
+class AppleWalletScreen extends React.Component<PropsWithContext> {
+  static navigationOptions = () => ({
+    headerStyle: {
+      backgroundColor: 'transparent',
+    },
+    headerTransparent: true,
+    headerTintColor: Color.white,
+  });
+
+  componentWillUnmount = () => {
+    this.props.setSelectedSegment(null);
+  };
+
+  render = () => (
     <View style={styles.container}>
       <AppleWalletScene />
     </View>
   );
 }
 
-AppleWalletScreen.navigationOptions = () => ({
-  headerStyle: {
-    backgroundColor: 'transparent',
-  },
-  headerTransparent: true,
-  headerTintColor: Color.white,
-});
+export default function AppleWalletScreenWithContext() {
+  return (
+    <WalletContext.Consumer>
+      {({ actions: { setSelectedSegment } }) => (
+        <AppleWalletScreen setSelectedSegment={setSelectedSegment} />
+      )}
+    </WalletContext.Consumer>
+  );
+}
 
 const styles = StyleSheet.create({
   container: {
diff --git a/app/MMB/src/scenes/appleWallet/__generated__/WalletContent.graphql.js b/app/MMB/src/scenes/appleWallet/__generated__/WalletContent.graphql.js
new file mode 100644
index 00000000..8fa047d0
--- /dev/null
+++ b/app/MMB/src/scenes/appleWallet/__generated__/WalletContent.graphql.js
@@ -0,0 +1,38 @@
+/**
+ * @flow
+ */
+
+/* eslint-disable */
+
+'use strict';
+
+/*::
+import type { ConcreteFragment } from 'relay-runtime';
+import type { FragmentReference } from "relay-runtime";
+declare export opaque type WalletContent$ref: FragmentReference;
+export type WalletContent = {|
+  +__typename?: string,
+  +$refType: WalletContent$ref,
+|};
+*/
+
+
+const node/*: ConcreteFragment*/ = {
+  "kind": "Fragment",
+  "name": "WalletContent",
+  "type": "Node",
+  "metadata": null,
+  "argumentDefinitions": [],
+  "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "__typename",
+      "args": null,
+      "storageKey": null
+    }
+  ]
+};
+// prettier-ignore
+(node/*: any*/).hash = '95ea8bd0a32b02b6d7fab3572e5c374b';
+module.exports = node;
diff --git a/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js b/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
index 5b832190..6edb9a02 100644
--- a/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
+++ b/app/MMB/src/scenes/tickets/__generated__/TicketRefetchQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash 09bf6763da79e19e856fcab514a6ed0e
+ * @relayHash a71e80c09d4a53918a865636a6978e00
  */
 
 /* eslint-disable */
@@ -96,6 +96,10 @@ fragment FlightSegments on Trip {
 }
 
 fragment FlightFromTo on Leg {
+  id
+  airline {
+    logoUrl
+  }
   departure {
     localTime
     airport {
@@ -134,6 +138,7 @@ fragment AppleWallet on BoardingPass {
 }
 
 fragment AppleWalletPassenger on Pkpass {
+  url
   passenger {
     fullName
   }
@@ -226,6 +231,24 @@ v5 = {
   "plural": true,
   "selections": [
     v2,
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "airline",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Airline",
+      "plural": false,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "logoUrl",
+          "args": null,
+          "storageKey": null
+        }
+      ]
+    },
     {
       "kind": "LinkedField",
       "alias": null,
@@ -278,6 +301,13 @@ v5 = {
           "concreteType": "Pkpass",
           "plural": true,
           "selections": [
+            {
+              "kind": "ScalarField",
+              "alias": null,
+              "name": "url",
+              "args": null,
+              "storageKey": null
+            },
             {
               "kind": "LinkedField",
               "alias": null,
@@ -317,7 +347,7 @@ return {
   "operationKind": "query",
   "name": "TicketRefetchQuery",
   "id": null,
-  "text": "query TicketRefetchQuery(\n  $id: ID!\n) {\n  node(id: $id) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
+  "text": "query TicketRefetchQuery(\n  $id: ID!\n) {\n  node(id: $id) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js b/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
index 93bd1f2b..03893ab0 100644
--- a/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
+++ b/app/MMB/src/scenes/tickets/__generated__/TicketSceneQuery.graphql.js
@@ -1,6 +1,6 @@
 /**
  * @flow
- * @relayHash ca5eaadbfbb6d991464b20e5cb85c590
+ * @relayHash 91eb81b2975e7a36d3451f46dc1b6c6c
  */
 
 /* eslint-disable */
@@ -96,6 +96,10 @@ fragment FlightSegments on Trip {
 }
 
 fragment FlightFromTo on Leg {
+  id
+  airline {
+    logoUrl
+  }
   departure {
     localTime
     airport {
@@ -134,6 +138,7 @@ fragment AppleWallet on BoardingPass {
 }
 
 fragment AppleWalletPassenger on Pkpass {
+  url
   passenger {
     fullName
   }
@@ -226,6 +231,24 @@ v5 = {
   "plural": true,
   "selections": [
     v2,
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "airline",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Airline",
+      "plural": false,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "logoUrl",
+          "args": null,
+          "storageKey": null
+        }
+      ]
+    },
     {
       "kind": "LinkedField",
       "alias": null,
@@ -278,6 +301,13 @@ v5 = {
           "concreteType": "Pkpass",
           "plural": true,
           "selections": [
+            {
+              "kind": "ScalarField",
+              "alias": null,
+              "name": "url",
+              "args": null,
+              "storageKey": null
+            },
             {
               "kind": "LinkedField",
               "alias": null,
@@ -317,7 +347,7 @@ return {
   "operationKind": "query",
   "name": "TicketSceneQuery",
   "id": null,
-  "text": "query TicketSceneQuery(\n  $bookingId: ID!\n) {\n  node(id: $bookingId) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
+  "text": "query TicketSceneQuery(\n  $bookingId: ID!\n) {\n  node(id: $bookingId) {\n    __typename\n    ... on BookingInterface {\n      ...TicketRefetch\n    }\n    id\n  }\n}\n\nfragment TicketRefetch on BookingInterface {\n  id\n  ...BoardingPasses\n  assets {\n    ...ETicket\n  }\n}\n\nfragment BoardingPasses on Node {\n  __typename\n  ... on BookingReturn {\n    ...BoardingPassReturn\n  }\n  ... on BookingOneWay {\n    ...BoardingPassOneWay\n  }\n  ... on BookingMulticity {\n    ...BoardingPassMultiCity\n  }\n}\n\nfragment ETicket on BookingAssets {\n  ticketUrl\n}\n\nfragment BoardingPassReturn on BookingReturn {\n  outbound {\n    ...FlightSegments\n  }\n  inbound {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassOneWay on BookingOneWay {\n  trip {\n    ...FlightSegments\n  }\n}\n\nfragment BoardingPassMultiCity on BookingMulticity {\n  trips {\n    arrival {\n      airport {\n        city {\n          name\n        }\n        id\n      }\n    }\n    ...FlightSegments\n  }\n}\n\nfragment FlightSegments on Trip {\n  legs {\n    id\n    ...FlightFromTo\n  }\n}\n\nfragment FlightFromTo on Leg {\n  id\n  airline {\n    logoUrl\n  }\n  departure {\n    localTime\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  arrival {\n    airport {\n      city {\n        name\n      }\n      id\n    }\n  }\n  boardingPass {\n    ...DownloadButton\n    ...AppleWallet\n  }\n}\n\nfragment DownloadButton on BoardingPass {\n  boardingPassUrl\n  ...BoardingPassInformation\n}\n\nfragment AppleWallet on BoardingPass {\n  pkpasses {\n    ...AppleWalletPassenger\n    passenger {\n      databaseId\n    }\n  }\n}\n\nfragment AppleWalletPassenger on Pkpass {\n  url\n  passenger {\n    fullName\n  }\n}\n\nfragment BoardingPassInformation on BoardingPass {\n  availableAt\n  boardingPassUrl\n  ...FutureBookingInformation\n}\n\nfragment FutureBookingInformation on BoardingPass {\n  boardingPassUrl\n}\n",
   "metadata": {},
   "fragment": {
     "kind": "Fragment",
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/FlightFromTo.js b/app/MMB/src/scenes/tickets/boardingPasses/FlightFromTo.js
index 56dfa3e5..f99cfb1f 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/FlightFromTo.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/FlightFromTo.js
@@ -10,57 +10,98 @@ import idx from 'idx';
 import AppleWallet from './appleWallet/AppleWallet';
 import DownloadButton from './DownloadButton';
 import type { FlightFromTo as RouteStopType } from './__generated__/FlightFromTo.graphql';
+import WalletContext, { type Segment } from '../../../context/WalletContext';
 
-type Props = {|
-  +data: RouteStopType,
+type PropsWithContext = {|
+  ...Props,
+  +addSegment: (segment: Segment) => void,
 |};
 
-export const FlightFromTo = (props: Props) => {
-  const date = idx(props.data, _ => _.departure.localTime);
-  const shortDate = date
-    ? DateFormatter(new Date(date)).formatToShortDate()
-    : '';
-  const time = date ? DateFormatter(new Date(date)).formatToTime() : '';
-  return (
-    <View style={styles.row}>
-      <View style={styles.dateContainer}>
-        <Text style={styles.dateText}>
-          <Translation passThrough={shortDate} />
-        </Text>
-        <Text style={styles.dateText}>
-          <Translation passThrough={time} />
-        </Text>
-      </View>
-      <View style={styles.rightColumn}>
-        <View style={[styles.row, styles.cityContainer]}>
-          <Text style={styles.cityText}>
-            <Translation
-              passThrough={idx(props.data, _ => _.departure.airport.city.name)}
-            />
+export class FlightFromTo extends React.Component<PropsWithContext> {
+  componentDidMount = () => {
+    const id = idx(this.props.data, _ => _.id) || '';
+    const airlineLogoUrl = idx(this.props.data, _ => _.airline.logoUrl) || '';
+    const flightDate = idx(this.props.data, _ => _.departure.localTime) || null;
+    this.props.addSegment({
+      id,
+      airlineLogoUrl,
+      flightDate,
+    });
+  };
+
+  render = () => {
+    const date = idx(this.props.data, _ => _.departure.localTime);
+    const shortDate = date
+      ? DateFormatter(new Date(date)).formatToShortDate()
+      : '';
+    const time = date ? DateFormatter(new Date(date)).formatToTime() : '';
+    return (
+      <View style={styles.row}>
+        <View style={styles.dateContainer}>
+          <Text style={styles.dateText}>
+            <Translation passThrough={shortDate} />
           </Text>
-          <TextIcon code="&#xe099;" style={styles.icon} />
-          <Text style={styles.cityText}>
-            <Translation
-              passThrough={idx(props.data, _ => _.arrival.airport.city.name)}
-            />
+          <Text style={styles.dateText}>
+            <Translation passThrough={time} />
           </Text>
         </View>
-        <View style={styles.buttonContainer}>
-          <DownloadButton data={idx(props.data, _ => _.boardingPass)} />
-        </View>
-        {Platform.OS === 'ios' && (
-          <View style={styles.appleWalletContainer}>
-            <AppleWallet data={idx(props.data, _ => _.boardingPass)} />
+        <View style={styles.rightColumn}>
+          <View style={[styles.row, styles.cityContainer]}>
+            <Text style={styles.cityText}>
+              <Translation
+                passThrough={idx(
+                  this.props.data,
+                  _ => _.departure.airport.city.name,
+                )}
+              />
+            </Text>
+            <TextIcon code="&#xe099;" style={styles.icon} />
+            <Text style={styles.cityText}>
+              <Translation
+                passThrough={idx(
+                  this.props.data,
+                  _ => _.arrival.airport.city.name,
+                )}
+              />
+            </Text>
+          </View>
+          <View style={styles.buttonContainer}>
+            <DownloadButton data={idx(this.props.data, _ => _.boardingPass)} />
           </View>
-        )}
+          {Platform.OS === 'ios' && (
+            <View style={styles.appleWalletContainer}>
+              <AppleWallet
+                segmentId={idx(this.props.data, _ => _.id)}
+                data={idx(this.props.data, _ => _.boardingPass)}
+              />
+            </View>
+          )}
+        </View>
       </View>
-    </View>
-  );
-};
+    );
+  };
+}
+
+type Props = {|
+  +data: RouteStopType,
+|};
+
+const FlightFromToWithContext = (props: Props) => (
+  <WalletContext.Consumer>
+    {({ actions: { addSegment } }) => (
+      <FlightFromTo {...props} addSegment={addSegment} />
+    )}
+  </WalletContext.Consumer>
+);
+
 export default createFragmentContainer(
-  FlightFromTo,
+  FlightFromToWithContext,
   graphql`
     fragment FlightFromTo on Leg {
+      id
+      airline {
+        logoUrl
+      }
       departure {
         localTime
         airport {
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/__generated__/FlightFromTo.graphql.js b/app/MMB/src/scenes/tickets/boardingPasses/__generated__/FlightFromTo.graphql.js
index 173855c7..97a9333f 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/__generated__/FlightFromTo.graphql.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/__generated__/FlightFromTo.graphql.js
@@ -13,6 +13,10 @@ type DownloadButton$ref = any;
 import type { FragmentReference } from "relay-runtime";
 declare export opaque type FlightFromTo$ref: FragmentReference;
 export type FlightFromTo = {|
+  +id: string,
+  +airline: ?{|
+    +logoUrl: ?string
+  |},
   +departure: ?{|
     +localTime: ?any,
     +airport: ?{|
@@ -73,6 +77,31 @@ return {
   "metadata": null,
   "argumentDefinitions": [],
   "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "id",
+      "args": null,
+      "storageKey": null
+    },
+    {
+      "kind": "LinkedField",
+      "alias": null,
+      "name": "airline",
+      "storageKey": null,
+      "args": null,
+      "concreteType": "Airline",
+      "plural": false,
+      "selections": [
+        {
+          "kind": "ScalarField",
+          "alias": null,
+          "name": "logoUrl",
+          "args": null,
+          "storageKey": null
+        }
+      ]
+    },
     {
       "kind": "LinkedField",
       "alias": null,
@@ -129,5 +158,5 @@ return {
 };
 })();
 // prettier-ignore
-(node/*: any*/).hash = 'fa049004b6ac398c3ce6798121384d21';
+(node/*: any*/).hash = 'c7701218d5d881a8c7be56c05b35dfae';
 module.exports = node;
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWallet.js b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWallet.js
index 079405f7..0337486b 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWallet.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWallet.js
@@ -12,6 +12,7 @@ import type { AppleWallet as Pkpasses } from './__generated__/AppleWallet.graphq
 
 type Props = {|
   +data: Pkpasses,
+  +segmentId: ?string,
 |};
 
 const AppleWallet = (props: Props) => {
@@ -33,6 +34,7 @@ const AppleWallet = (props: Props) => {
           <AppleWalletPassenger
             key={idx(item, _ => _.passenger.databaseId)}
             data={item}
+            segmentId={props.segmentId}
           />
         ))}
       </View>
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWalletPassenger.js b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWalletPassenger.js
index 5d8e024b..da9cbfec 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWalletPassenger.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/AppleWalletPassenger.js
@@ -11,14 +11,21 @@ import {
 } from '@kiwicom/mobile-navigation';
 
 import type { AppleWalletPassenger as AppleWalletType } from './__generated__/AppleWalletPassenger.graphql';
+import WalletContext from './../../../../context/WalletContext';
 
-type Props = {|
-  +data: AppleWalletType,
-  +navigation: NavigationType,
+type PropsWithContext = {|
+  ...Props,
+  addPkpassData: (passengerName: string, pkpassUrl: string, id: string) => void,
 |};
 
-class AppleWalletPassenger extends React.Component<Props> {
+class AppleWalletPassenger extends React.Component<PropsWithContext> {
   onPress = () => {
+    const name = idx(this.props.data, _ => _.passenger.fullName) || '';
+    const url = idx(this.props.data, _ => _.url) || '';
+
+    if (this.props.segmentId != null) {
+      this.props.addPkpassData(name, url, this.props.segmentId);
+    }
     this.props.navigation.navigate('AppleWalletScreen');
   };
 
@@ -34,10 +41,25 @@ class AppleWalletPassenger extends React.Component<Props> {
   );
 }
 
+type Props = {|
+  +data: AppleWalletType,
+  +navigation: NavigationType,
+  +segmentId: ?string,
+|};
+
+const AppleWalletPassengerWithContext = (props: Props) => (
+  <WalletContext.Consumer>
+    {({ actions: { addPkpassData } }) => (
+      <AppleWalletPassenger {...props} addPkpassData={addPkpassData} />
+    )}
+  </WalletContext.Consumer>
+);
+
 export default createFragmentContainer(
-  withNavigation(AppleWalletPassenger),
+  withNavigation(AppleWalletPassengerWithContext),
   graphql`
     fragment AppleWalletPassenger on Pkpass {
+      url
       passenger {
         fullName
       }
diff --git a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/__generated__/AppleWalletPassenger.graphql.js b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/__generated__/AppleWalletPassenger.graphql.js
index f142cd80..81170769 100644
--- a/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/__generated__/AppleWalletPassenger.graphql.js
+++ b/app/MMB/src/scenes/tickets/boardingPasses/appleWallet/__generated__/AppleWalletPassenger.graphql.js
@@ -11,6 +11,7 @@ import type { ConcreteFragment } from 'relay-runtime';
 import type { FragmentReference } from "relay-runtime";
 declare export opaque type AppleWalletPassenger$ref: FragmentReference;
 export type AppleWalletPassenger = {|
+  +url: ?string,
   +passenger: ?{|
     +fullName: ?string
   |},
@@ -26,6 +27,13 @@ const node/*: ConcreteFragment*/ = {
   "metadata": null,
   "argumentDefinitions": [],
   "selections": [
+    {
+      "kind": "ScalarField",
+      "alias": null,
+      "name": "url",
+      "args": null,
+      "storageKey": null
+    },
     {
       "kind": "LinkedField",
       "alias": null,
@@ -47,5 +55,5 @@ const node/*: ConcreteFragment*/ = {
   ]
 };
 // prettier-ignore
-(node/*: any*/).hash = 'ba46f5a1076aacd79647709654ecd6bb';
+(node/*: any*/).hash = '61c60dd20c79385de68ba4be12f67a04';
 module.exports = node;


Test patch:
diff --git a/app/MMB/src/context/__tests__/WalletContext.test.js b/app/MMB/src/context/__tests__/WalletContext.test.js
new file mode 100644
index 00000000..371c98ee
--- /dev/null
+++ b/app/MMB/src/context/__tests__/WalletContext.test.js
@@ -0,0 +1,99 @@
+// @flow strict
+
+import * as React from 'react';
+import renderer from 'react-test-renderer';
+import MockDate from 'mockdate';
+
+import WalletContext from '../WalletContext';
+
+MockDate.set('2018-01-01');
+
+class ContextConsumer extends React.Component<{}> {
+  render = () => null;
+}
+
+const getWrapper = () =>
+  renderer.create(
+    <WalletContext.Provider>
+      <WalletContext.Consumer>
+        {({
+          actions: { addSegment, addPkpassData, setSelectedSegment },
+          ...rest
+        }) => (
+          <ContextConsumer
+            {...rest}
+            addSegment={addSegment}
+            addPkpassData={addPkpassData}
+            setSelectedSegment={setSelectedSegment}
+          />
+        )}
+      </WalletContext.Consumer>
+    </WalletContext.Provider>,
+  );
+
+const segment1 = {
+  id: '123',
+  airlineLogoUrl: 'lol',
+  flightDate: new Date(),
+};
+const segment2 = {
+  id: '1234',
+  airlineLogoUrl: 'lollo',
+  flightDate: new Date(),
+};
+
+describe('WalletContext', () => {
+  it('injects the props to consumers', () => {
+    const wrapper = getWrapper();
+
+    const instance = wrapper.root.findByType(ContextConsumer);
+    expect(instance.props.segments).toEqual([]);
+    expect(instance.props.selectedSegment).toBe(null);
+
+    expect(typeof instance.props.addSegment).toBe('function');
+    expect(typeof instance.props.addPkpassData).toBe('function');
+    expect(typeof instance.props.setSelectedSegment).toBe('function');
+  });
+
+  it('adds segment', () => {
+    const wrapper = getWrapper();
+    const instance = wrapper.root.findByType(ContextConsumer);
+
+    instance.props.addSegment(segment1);
+    expect(instance.props.segments).toEqual([segment1]);
+
+    instance.props.addSegment(segment2);
+    expect(instance.props.segments).toEqual([segment1, segment2]);
+  });
+
+  it('adds pkpass data', () => {
+    const wrapper = getWrapper();
+    const instance = wrapper.root.findByType(ContextConsumer);
+
+    instance.props.addSegment(segment1);
+    instance.props.addSegment(segment2);
+    instance.props.addPkpassData('Passenger', 'url', segment1.id);
+
+    const expectedResult = {
+      ...segment1,
+      passengerName: 'Passenger',
+      pkpassUrl: 'url',
+    };
+    expect(instance.props.segments).toEqual([expectedResult, segment2]);
+    expect(instance.props.selectedSegment).toEqual(expectedResult);
+  });
+
+  it('sets selected segment', () => {
+    const wrapper = getWrapper();
+    const instance = wrapper.root.findByType(ContextConsumer);
+
+    instance.props.addSegment(segment1);
+    instance.props.addSegment(segment2);
+
+    instance.props.setSelectedSegment(segment1.id);
+    expect(instance.props.selectedSegment).toEqual(segment1);
+
+    instance.props.setSelectedSegment(null);
+    expect(instance.props.selectedSegment).toBe(null);
+  });
+});