@@ -14,6 +14,8 @@ import os
1414public struct MapFeature {
1515 enum Constants {
1616 static let defaultInitialPosition : CLLocation = . init( latitude: 37.498095 , longitude: 127.027610 )
17+ static let cameraTargetDistanceThreshold : CLLocationDistance = 200
18+ static let regionChangeDistanceThreshold : CLLocationDistance = 500
1719 }
1820
1921 enum SheetStage {
@@ -41,6 +43,7 @@ public struct MapFeature {
4143 // Map State
4244 var cameraPosition : GeographicCoordinate ?
4345 var currentBounds : GeographicBoundingBox ?
46+ var lastSearchedLocation : CLLocation ?
4447
4548 // User Location
4649 var locationAuthorizationStatus : CLAuthorizationStatus = . notDetermined
@@ -109,6 +112,7 @@ public struct MapFeature {
109112 case processNewChunk( [ PhotoBooth ] , isFirstBatch: Bool )
110113 case appendProcessedChunk( map: [ PhotoBooth ] , isFirstBatch: Bool )
111114 case didFinishBackgroundCalculation( map: IdentifiedArrayOf < PhotoBooth > , list: IdentifiedArrayOf < PhotoBooth > )
115+ case didSelectDirectionApp( DirectionAppType )
112116
113117 // Binding & Child
114118 case binding( BindingAction < State > )
@@ -126,6 +130,7 @@ public struct MapFeature {
126130
127131 @Dependency ( \. mapClient) private var mapClient
128132 @Dependency ( \. photoBoothClient) private var photoBoothClient
133+ @Dependency ( \. analyticsClient) private var analytics
129134 @Dependency ( \. openURL) private var openURL
130135
131136 public var body : some ReducerOf < Self > {
@@ -261,18 +266,14 @@ public struct MapFeature {
261266
262267 guard state. isFirstLoad else { return . none }
263268 guard state. locationAuthorizationStatus != . notDetermined else { return . none }
264- let targetCoordinate : CLLocation
265- if state. isLocationAuthorized {
266- guard let userLocation = state. userLocation else { return . none }
267- targetCoordinate = userLocation
268- } else {
269- targetCoordinate = Constants . defaultInitialPosition
270- }
271269
270+ let targetCoordinate = state. isLocationAuthorized ? ( state. userLocation ?? Constants . defaultInitialPosition) : Constants . defaultInitialPosition
272271 let currentCameraLocation = CLLocation ( latitude: bounds. center. latitude, longitude: bounds. center. longitude)
273- guard currentCameraLocation. distance ( from: targetCoordinate) <= 200 else { return . none }
272+
273+ guard currentCameraLocation. distance ( from: targetCoordinate) <= Constants . cameraTargetDistanceThreshold else { return . none }
274274 state. isFirstLoad = false
275275 let nearbyTargetCoordinate = state. userGeographicCoordinate ?? bounds. center
276+ state. lastSearchedLocation = currentCameraLocation
276277 return . merge(
277278 . send( . fetchPhotoBooths( bounds: bounds) ) ,
278279 . send( . fetchNearbyPhotoBooths( nearbyTargetCoordinate) )
@@ -285,7 +286,13 @@ public struct MapFeature {
285286 case . didTapSearchHereButton:
286287 guard let bounds = state. currentBounds else { return . none }
287288 let nearbyTargetCoordinate = state. userGeographicCoordinate ?? bounds. center
289+ let currentCenterLocation = CLLocation ( latitude: bounds. center. latitude, longitude: bounds. center. longitude)
290+ let isRegionChanged = checkIfRegionChanged ( from: state. lastSearchedLocation, to: currentCenterLocation)
291+ let hasFilter = state. photoBoothListState. filteredBrands. isEmpty == false
292+ let event = MapAnalyticsEvent . mapReSearch ( hasFilter: hasFilter, regionChanged: isRegionChanged)
293+ state. lastSearchedLocation = currentCenterLocation
288294 return . merge(
295+ . run { _ in analytics. logEvent ( event: event) } ,
289296 . send( . fetchPhotoBooths( bounds: bounds) ) ,
290297 . send( . fetchNearbyPhotoBooths( nearbyTargetCoordinate) )
291298 )
@@ -392,7 +399,8 @@ public struct MapFeature {
392399 case . didTapBooth( let photoBooth) :
393400 state. isUserTrackingMode = false
394401 selectPhotoBooth ( & state, photoBooth: photoBooth)
395- return . none
402+ let event = MapAnalyticsEvent . boothSelect ( brandName: photoBooth. brand. name, entryPoint: . map)
403+ return . run { _ in analytics. logEvent ( event: event) }
396404
397405 case . didTapBoothCard:
398406 state. isUserTrackingMode = false
@@ -408,6 +416,15 @@ public struct MapFeature {
408416 state. directionSheetPhotoBooth = state. selectedBooth
409417 return . none
410418
419+ case let . didSelectDirectionApp( appType) :
420+ guard let photoBooth = state. directionSheetPhotoBooth else { return . none }
421+ guard let url = appType. connectLink ( coordinate: photoBooth. coordinate, name: photoBooth. name) else { return . none }
422+ state. directionSheetPhotoBooth = nil
423+ return . merge(
424+ . run { _ in analytics. logEvent ( event: MapAnalyticsEvent . mapRouteClick ( mapType: appType) ) } ,
425+ . run { _ in await openURL ( url) }
426+ )
427+
411428 case . updateSDKAuthStatus( let isAuthorized) :
412429 state. isSDKAuthSuccessful = isAuthorized
413430 return . none
@@ -416,7 +433,10 @@ public struct MapFeature {
416433 return . send( . startBackgroundCalculation)
417434
418435 case let . photoBoothListAction( . didTapBooth( photoBooth) ) :
419- return . send( . didTapBooth( photoBooth) )
436+ state. isUserTrackingMode = false
437+ selectPhotoBooth ( & state, photoBooth: photoBooth)
438+ let event = MapAnalyticsEvent . boothSelect ( brandName: photoBooth. brand. name, entryPoint: . bottomSheet)
439+ return . run { _ in analytics. logEvent ( event: event) }
420440
421441 default :
422442 return . none
@@ -444,4 +464,9 @@ private extension MapFeature {
444464 func updateCameraPosition( _ state: inout State , to coordinate: CLLocationCoordinate2D ) {
445465 state. cameraPosition = . init( latitude: coordinate. latitude, longitude: coordinate. longitude)
446466 }
467+
468+ func checkIfRegionChanged( from lastLocation: CLLocation ? , to currentLocation: CLLocation ) -> Bool {
469+ guard let lastLocation else { return false }
470+ return currentLocation. distance ( from: lastLocation) >= Constants . regionChangeDistanceThreshold
471+ }
447472}
0 commit comments