Booking Request Component

The booking request component takes a quote and outputs a booked trip or an error when booking the quote.

417

iOS Sample

📘

Payment flow handling

The booking request component requires a URL scheme to be set for the braintree SDK to fully manage 3DSecure payment flows. Please follow this guide for adding a URL Scheme to successfully handle app switching for the iOS implementation.

The booking request is implemented as a ViewController to automatically handle the presentation, dismissal and handling of the payment flow.

private var bookingStatus = KarhooBookingStatus.shared
let bookingScreenBuilderResult = KarhooUI().screens()
                                           .bookingRequest()
                                           .buildBookingScreen(quote: quote,
                                                              bookingDetails: bookingStatus.getBookingDetails()!,
                                                              bookingMetadata: nil,
                                                              callback: { [weak self] result in
            if let bookingResult = result.completedValue() {
                switch bookingResult {
                case .tripAllocated(let trip): // user booked a trip
                case .bookingFailed(let error): // there was an error booking a trip
                case .prebookConfirmed(let trip, let prebookAction): // the user prebooked a trip for a later date
                }
            }
        })

        guard let bookingScreen = bookingScreenBuilderResult.screen() else {
            print("error building karhoo booking screen: \(bookingScreenBuilderResult.error())")
            return
        }

        bookingScreen.modalPresentationStyle = .fullScreen
        self.present(bookingScreen)

Android Sample

Add the View to your layout

<com.karhoo.uisdk.screen.booking.booking.bookingrequest.BookingRequestView
        android:id="@+id/booking_request_widget"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

Initialise the View in your Activity or Fragment. Example shown below is for a Fragment.

//Instantiate BookingQuotesViewModel
private lateinit var bookingQuotesViewModel: BookingQuotesViewModel by lazy {
    ViewModelProvider(this).get(BookingStatusStateViewModel::class.java)
}
//Instantiate BookingStatusStateViewModel
private val bookingStatusStateViewModel: BookingStatusStateViewModel by lazy {
    ViewModelProvider(this).get(BookingStatusStateViewModel::class.java)
}
//Instantiate BookingRequestStateViewModel
private lateinit var bookingRequestStateViewModel: BookingRequestStateViewModel by lazy {
    ViewModelProvider(this).get(BookingRequestStateViewModel::class.java)
}
private var quote: Quote? = null

Bind the Views and observe the outputs

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    //Setup the Booking Request Component
    booking_request_widget.apply {
        bindViewToBookingStatus(requireActivity(), bookingStatusStateViewModel)
        bindViewToBookingRequest(requireActivity(), bookingRequestStateViewModel)
    }
    //Set up the observer for the actions and outputs
    bookingQuotesViewModel.viewStates().observe(owner, createQuoteObservable())
    bookingRequestStateViewModel.viewActions().observe(this, bindToBookingRequestOutputs())
}

private fun createQuoteObservable(): Observer<QuoteListStatus> {
    return Observer { it ->
        it.let { quote ->
            val selectedQuote = quote.selectedQuote
            this.quote = selectedQuote
            this.quote?.let {
                booking_request_widget?.showBookingRequest(it, null)
            }
        }
    }
}

private fun bindToBookingRequestOutputs(): Observer<in BookingRequestViewContract.BookingRequestAction> {
    return Observer { actions ->
        when (actions) {
            is BookingRequestViewContract.BookingRequestAction.ShowTermsAndConditions -> {
                //Use the url to show the user the terms and conditions e.g.
                val intent = Intent(context, WebActivity::class.java)
                intent.putExtra(EXTRA_URL, actions.url)
                startActivity(intent)
            }
            is BookingRequestViewContract.BookingRequestAction.WaitForTripAllocation ->
                //Handle the wait when the booking has been made and the driver allocation is in progress
                waitForTripAllocation()
            is BookingRequestViewContract.BookingRequestAction.HandleBookingError ->
                //Handle errors
                showErrorDialog(actions.stringId)
        }
    }
}

Handle the payment result returned by Braintree

//You will need to call this from the Activity if you're not using fragments
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == REQ_CODE_BRAINTREE || requestCode == REQ_CODE_BRAINTREE_GUEST || requestCode == AdyenPaymentView.REQ_CODE_ADYEN) {
        booking_request_widget.onActivityResult(requestCode, resultCode, data)
    }
}

companion object {
    const val REQ_CODE_BRAINTREE = 301
    const val REQ_CODE_BRAINTREE_GUEST = 302
}