chromium/ios/chrome/browser/parcel_tracking/parcel_tracking_util.mm

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/parcel_tracking/parcel_tracking_util.h"

#import <string>
#import <vector>

#import "base/functional/bind.h"
#import "base/functional/callback_helpers.h"
#import "base/strings/sys_string_conversions.h"
#import "components/commerce/core/commerce_types.h"
#import "components/commerce/core/shopping_service.h"
#import "components/signin/public/base/consent_level.h"
#import "ios/chrome/browser/commerce/model/shopping_service_factory.h"
#import "ios/chrome/browser/ntp/shared/metrics/home_metrics.h"
#import "ios/chrome/browser/parcel_tracking/features.h"
#import "ios/chrome/browser/parcel_tracking/metrics.h"
#import "ios/chrome/browser/parcel_tracking/parcel_tracking_opt_in_status.h"
#import "ios/chrome/browser/parcel_tracking/parcel_tracking_prefs.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/prefs/pref_names.h"
#import "ios/chrome/browser/shared/public/commands/parcel_tracking_opt_in_commands.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_constants.h"

namespace {
const CGFloat parcelLimit = 5;
}  // namespace

bool IsUserEligibleParcelTrackingOptInPrompt(
    PrefService* pref_service,
    commerce::ShoppingService* shopping_service) {
  return IsIOSParcelTrackingEnabled() &&
         !IsParcelTrackingDisabled(
             IsHomeCustomizationEnabled()
                 ? pref_service
                 : GetApplicationContext()->GetLocalState()) &&
         !pref_service->GetBoolean(
             prefs::kIosParcelTrackingOptInPromptDisplayLimitMet) &&
         shopping_service->IsParcelTrackingEligible();
}

std::vector<std::pair<commerce::ParcelIdentifier::Carrier, std::string>>
ConvertCustomTextCheckingResult(NSArray<CustomTextCheckingResult*>* result) {
  std::vector<std::pair<commerce::ParcelIdentifier::Carrier, std::string>>
      new_parcel_list;
  for (CustomTextCheckingResult* parcel : result) {
    commerce::ParcelIdentifier::Carrier carrier =
        static_cast<commerce::ParcelIdentifier::Carrier>(parcel.carrier);
    std::string tracking_number = base::SysNSStringToUTF8(parcel.carrierNumber);
    new_parcel_list.push_back(std::make_pair(carrier, tracking_number));
  }
  return new_parcel_list;
}

void TrackParcels(
    commerce::ShoppingService* shopping_service,
    NSArray<CustomTextCheckingResult*>* parcels,
    std::string domain,
    id<ParcelTrackingOptInCommands> parcel_tracking_commands_handler,
    bool display_infobar,
    TrackingSource source) {
  shopping_service->StartTrackingParcels(
      ConvertCustomTextCheckingResult(parcels), domain,
      base::BindOnce(
          [](bool display_infobar,
             id<ParcelTrackingOptInCommands> parcel_tracking_commands_handler,
             NSArray<CustomTextCheckingResult*>* parcels, TrackingSource source,
             bool success,
             std::unique_ptr<std::vector<commerce::ParcelTrackingStatus>>
                 parcel_status) {
            if (success) {
              RecordModuleFreshnessSignal(
                  ContentSuggestionsModuleType::kParcelTracking);
              parcel_tracking::RecordParcelsTracked(source, parcels.count);
              if (display_infobar) {
                [parcel_tracking_commands_handler
                    showParcelTrackingInfobarWithParcels:parcels
                                                 forStep:
                                                     ParcelTrackingStep::
                                                         kNewPackageTracked];
              }
            }
          },
          display_infobar, parcel_tracking_commands_handler, parcels, source));
}

void FilterParcelsAndShowParcelTrackingUI(
    commerce::ShoppingService* shopping_service,
    NSArray<CustomTextCheckingResult*>* parcels,
    id<ParcelTrackingOptInCommands> parcel_tracking_commands_handler) {
  shopping_service->GetAllParcelStatuses(base::BindOnce(
      [](id<ParcelTrackingOptInCommands> parcel_tracking_commands_handler,
         NSArray<CustomTextCheckingResult*>* parcels, bool success,
         std::unique_ptr<std::vector<commerce::ParcelTrackingStatus>>
             statuses) {
        NSMutableSet* parcel_numbers = [NSMutableSet
            setWithArray:[parcels valueForKeyPath:@"carrierNumber"]];
        // Remove the tracking numbers of already tracked parcels from
        // parcel_numbers array.
        for (commerce::ParcelTrackingStatus status : *statuses) {
          NSString* tracking_id = base::SysUTF8ToNSString(status.tracking_id);
          if ([parcel_numbers containsObject:tracking_id]) {
            [parcel_numbers removeObject:tracking_id];
          }
        }
        // Add the remaining parcels to filtered_parcels array.
        NSMutableArray<CustomTextCheckingResult*>* filtered_parcels =
            [[NSMutableArray alloc] init];
        for (CustomTextCheckingResult* parcel : parcels) {
          if ([parcel_numbers containsObject:parcel.carrierNumber]) {
            [filtered_parcels addObject:parcel];
          }
        }
        // Only track or offer to track when number of packages is less than 6.
        if (filtered_parcels.count > 0 &&
            filtered_parcels.count <= parcelLimit) {
          [parcel_tracking_commands_handler
              showTrackingForFilteredParcels:filtered_parcels];
        }
      },
      parcel_tracking_commands_handler, parcels));
}