Development Journey of LINE TAXI: My Top 3 Favorite Features in 2023

Published on

As a member of the LINE TAXI, I've been involved in the team for nearly three years. In the first year, I primarily maintained internal website and had relatively limited experience with large-scale projects. In the second year, I transitioned to the core product line and started working on the development of the ride-hailings application. From map rendering, address input, to ride matching, I collaborated closely with product managers, designers, QA engineers, and other stakeholders to continuously improve user experience while maintaining system performance. During this period, we launched many innovative features, which helped me grow rapidly.

2023 was a special year for LINE TAXI. Due to a shift in the group's strategy, we decided to expand our business scope and rebrand. Therefore, LINE TAXI will be officially renamed to LINE GO.

Before saying goodbye to the LINE TAXI brand, I would like to share in this article the three features I am most satisfied with that I developed in 2023.


🌿 Address Reordering: Enhancing User Experience

Background and Rationale

Many users are familiar with Google Maps' ability to allow users to input multiple addresses and reorder them by dragging and dropping. As a ride-hailing platform, route planning is a core feature. We frequently received feedback from users that they often mistakenly typed their origin and destination, requiring them to re-enter the addresses.

To address this issue and enhance user experience, we proposed an innovative solution in our team workshop: a drag-and-drop feature for reordering addresses.

Development Considerations

To implement this feature within a tight deadline, I conducted a research on popular drag-and-drop libraries. Considering factors such as maintenance cost, API ease of use, and performance, I finally selected react-beautiful-dnd, a powerful React drag-and-drop library. This library is specifically designed for list items, making it an ideal fit for our address reordering requirements.

By wrapping each address item in the Draggable component, I can easily handle address reordering updates within the onDragEnd callback when the user finishes dragging

onDragEnd = (e) => {
  const { destination, source } = e
  // if the position didn't change, return
  if (!destination || destination.index === source.index) return
  /**
  address dragging swapping logic: 
    * 1. get origin list and compare to the list in new order
    * 2. set first address as pick-up location
    * 3. check the status of pick-up location
    * 4. update list
  */

  // ...omit business logic
  const newAddressList = cloneDeep(listInNewOrder)
  setAddressList(newAddressList)
  setDragging(false)
}

Results and Feedback

Within a week of launching the feature, we have received a significant amount of positive feedback from our users. One particularly heartwarming message came from a busy mother who shared how she often accidentally swapped her home and school addresses, wasting time re-entering the information. The new feature has allowed her to easily adjust the address order, significantly improving her efficiency. This positive feedback is incredibly rewarding and reaffirms my commitment to continuously enhancing the user experience.


🌿 Expanding Vehicle Options

Background and Rationale

LINE TAXI currently offers ride-hailing services primarily through metered taxis and flat-rate vehicles. However, user needs are becoming diverse, with requirements such as transporting infants, pets, or accessible needs. Previously, we allowed users to note special requests, but the decision of whether to accept the order was left to the driver. To better meet user needs, we plan to divide vehicle types, allowing users to more easily select the vehicle that best suits their needs.

Development Considerations

Initially, the platform only supported two types of vehicles, and the related data was hardcoded in the frontend. To accommodate the potential addition of new vehicle types in the future and improve system flexibility, we decided to refactor the system as follows:

  1. Move vehicle information from the frontend to the backend API
  2. Rewrite related functionalities using React Hooks to improve code readability
  3. Modularize components for easier reuse and increased development efficiency

Results and Feedback

We have successfully launched the feature in the northern region. Users can now easily see which vehicle types are available in their area when estimating fares, eliminating the need for additional notes and reducing the likelihood of driver rejection.

The "Choose Any Vehicle Type" option has been well-received by users. Users no longer need to spend time understanding the differences between various vehicle types; they can simply request a ride with a single click. This significantly improves user efficiency and meets their demand for convenient transportation.


🌿 Swipeable List: Achieving Native-Like Smoothness on the Web

Background and Rationale

The great majority of LINE TAXI users access our service through mobile devices and the LINE app. To provide a user experience closer to native apps, our design team aimed to implement a swipeable list feature on our web interface.

Development Considerations

Initially, I believed that implementing a swipeable list using React would be relatively straightforward. However, after extensive research, I discovered that there were no off-the-shelf components that perfectly met our requirements. This presented a new challenge for me.

I broke down this task into two core components:

  • Smooth Animations: I used the react-spring library to provide natural, smooth animations for list elements.
  • Gesture Handling: I employed the use-gesture library to accurately capture user gestures and translate them into corresponding animations.

After several weeks of tuning and optimization, I successfully created a swipeable list that closely resembles the native app experience.

import React, { useEffect, useRef, useCallback } from 'react'
import { useSpring, animated } from '@react-spring/web'
import { useDrag } from '@use-gesture/react'

// Constrain the draggable height between the minimum and maximum values
const clamp = (value, min, max) => Math.max(min, Math.min(max, value))

const SwipeBottomSheet = ({ children, isBottomSheetExpanded, seBottomSheetExpand, minHeight }) => {
  const currentDirectionRef = useRef()

  const [{ y }, set] = useSpring(() => {
    return {
      y: MIN_SHEET_HEIGHT,
      config: { tension: 170, friction: 26 }, // animation effects
    }
  })

  const bind = useDrag(({ down, movement: [, my], direction, memo = y.get() }) => {
    if (direction[0] !== direction[1]) {
      // ...Record the direction at the beginning of the drag gesture
    }

    // when stop dragging
    let finalHeight
    const moveY = Math.abs(my)
    if (!down) {
      finalHeight = isBottomSheetExpanded ? MAX_SHEET_HEIGHT : MIN_SHEET_HEIGHT
      if (currentDirectionRef.current === DIRECTION.UP) {
        // ...if the upward drag exceeds half the height of the box -> expand
      } else if (currentDirectionRef.current === DIRECTION.DOWN) {
        // ...if the downward drag exceeds half the height of the box -> collapse
      }
    }
    const newY = down ? memo - my : finalHeight
    set({ y: newY, immediate: down })
    return memo
  })

  return (
    <animated.div
      {...bind()}
      style={{
        height: y.to(
          (value) =>
            `${
              isBottomSheetExpanded
                ? MAX_SHEET_HEIGHT
                : clamp(value, MIN_SHEET_HEIGHT, MAX_SHEET_HEIGHT)
            }px`
        ),
      }}
    >
      {children}
    </animated.div>
  )
}

export default SwipeBottomSheet

Results and Feedback

This swipeable list component is one of my most satisfying feature this year. Upon its launch, it received high praise from the LINE headquarters design team. We were the first team at LINE to implement a native-like swiping experience on the web.

To enhance code reusability, I modularized this component so that it can be used in multiple scenarios such as rental services and trip interfaces.