Skip to content

Conversation

@mkouzel-yext
Copy link
Contributor

@mkouzel-yext mkouzel-yext commented Nov 5, 2025

When searching for countries in the locator filtersearch bar (e.g. "United States"), the static filter returned by filtersearch is

{
  "address.countryCode": {
    "$eq": "US"
  }
}

instead of a {"$near": {lat, lng, radius}} filter. This adds handling to the locator to support this type of filter, and also updates distance and clear filters click handlers to only update near filter radii.

J=WAT-5171
TEST=manual

jam:https://jam.dev/c/04a22a5c-4d95-4d89-9e31-3f7f0bc1ed0a

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Warning: Component files have been updated but no migrations have been added. See https://github.com/yext/visual-editor/blob/main/packages/visual-editor/src/components/migrations/README.md for more information.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

The pull request refactors Locator.tsx filter handling to branch by filter.matcher (Matcher.Near vs Matcher.Equals), deriving a local nearFilterValue for Near (and augmenting radius) and using filter.value for Equals; unsupported matchers throw. Map centering now uses nearFilterValue.lat/nearFilterValue.lng when present. Distance/location filter updates are reworked to identify filters via new helpers (isLocationNearFilter, isOpenNowFilter), segment and replace near-location filters, compose static filters by concatenating non-location near-filters with updated near-location filters, and update Open Now and location-near filters together to avoid races. The internal Location interface was expanded with additional fields.

Sequence Diagram

sequenceDiagram
    participant User
    participant Locator as Locator Component
    participant Handler as handleFilterSelect

    User->>Locator: selects filter
    Locator->>Handler: handleFilterSelect(filter)

    alt filter.matcher == Matcher.Near
        note right of Handler `#DDEBF7`: derive nearFilterValue\naugment radius
        Handler->>Handler: build locationFilter using nearFilterValue & fieldId
        Handler->>Locator: setMapCenter(nearFilterValue.lat, nearFilterValue.lng)
    else filter.matcher == Matcher.Equals
        note right of Handler `#F7E7D7`: use filter.value directly
        Handler->>Handler: build locationFilter using filter.value
    else Unsupported matcher
        Handler->>Handler: throw Error("Unsupported matcher")
    end

    note right of Handler `#F3F4F6`: identify existing filters\nusing isLocationNearFilter & isOpenNowFilter
    Handler->>Handler: segment old vs updated location filters
    Handler->>Handler: compose staticFilters = non-location-near + updated-location-near
    Handler->>Locator: update state with new staticFilters and map center
Loading

Possibly related PRs

Suggested reviewers

  • benlife5
  • asanehisa

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding support for the equals matcher ($eq) in static filters for the locator component.
Description check ✅ Passed The description provides clear context about the problem (equals matcher filters for country searches) and the solution (handling support for $eq filters and updating radius handlers).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch handle-equals-filters-locator

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de0ca72 and 86206ce.

📒 Files selected for processing (1)
  • packages/visual-editor/src/components/Locator.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.
📚 Learning: 2025-10-29T22:00:03.843Z
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.

Applied to files:

  • packages/visual-editor/src/components/Locator.tsx
🔇 Additional comments (4)
packages/visual-editor/src/components/Locator.tsx (4)

688-736: Well-structured matcher branching logic.

The refactoring to use a switch statement for handling different matcher types is clean and maintainable. The separate handling for Matcher.Near (with radius injection) and Matcher.Equals (direct value pass-through) aligns well with the PR objective of supporting country code filters.


947-987: LGTM!

The distance filter update logic correctly uses the new isLocationNearFilter helper to isolate and update only near-location filters while preserving other static filters. The separation makes the intent clear and ensures that only radius values on near filters are modified.


1668-1674: Good abstraction with helper functions.

The isLocationNearFilter and isOpenNowFilter helpers improve code readability and reduce duplication. The explicit checks for field ID, kind, and matcher make the filter identification logic clear and maintainable.


1676-1687: LGTM!

The expanded Location interface correctly reflects the fields used throughout the component (e.g., mainPhone at lines 1333-1340, yextDisplayCoordinate at line 1356). The optional typing aligns with the defensive checks in the rendering logic.

@mkouzel-yext mkouzel-yext requested review from a team November 5, 2025 18:18
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/visual-editor/src/components/Locator.tsx (1)

724-725: Consider graceful error handling instead of throwing.

Throwing an error for unsupported matchers will crash the component in production. Consider logging a warning and falling back to a safe default behavior (e.g., using the filter as-is or skipping the update) to maintain a better user experience.

Apply this diff to handle unsupported matchers gracefully:

     default:
-      throw new Error(`Unsupported matcher type: ${filter.matcher}`);
+      console.warn(`Unsupported matcher type: ${filter.matcher}`);
+      locationFilter = {
+        displayName: newDisplayName,
+        selected: true,
+        filter: {
+          kind: "fieldValue",
+          fieldId: filter.fieldId,
+          value: filter.value,
+          matcher: filter.matcher as Matcher,
+        },
+      };
+      break;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86206ce and 667dd05.

📒 Files selected for processing (1)
  • packages/visual-editor/src/components/Locator.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.
📚 Learning: 2025-10-29T22:00:03.843Z
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.

Applied to files:

  • packages/visual-editor/src/components/Locator.tsx
🔇 Additional comments (6)
packages/visual-editor/src/components/Locator.tsx (6)

731-735: Verify map centering behavior for Equals filters.

When an Equals filter is selected (e.g., countryCode: {$eq: "US"}), nearFilterValue will be undefined, so the map won't re-center. This might be intentional for non-geographic filters, but could be unexpected if users search for a location name that returns an Equals filter instead of a Near filter.

Consider documenting this behavior or adding a comment explaining why Equals filters don't trigger map re-centering.


950-982: LGTM! Distance handling correctly filters by location Near matcher.

The refactor correctly identifies location Near filters using the new isLocationNearFilter helper and updates only those filters' radii. Non-Near filters (including location Equals filters) are preserved without modification, which is the correct behavior.


994-1043: LGTM! Clear filters handling is correct.

The refactor correctly:

  • Uses && operator (line 995) to exclude both Open Now and location Near filters from unaffected filters
  • Updates both filter types in a single setStaticFilters call (lines 1038-1042) to avoid race conditions
  • Resets location Near filters to default radius

Note: The logical operator issue flagged in the previous review has been resolved.


1668-1674: LGTM! Helper functions improve code clarity.

The new helper functions isLocationNearFilter and isOpenNowFilter correctly identify specific filter types and are used consistently throughout the file. The isLocationNearFilter helper appropriately checks for the Near matcher specifically, which is essential for the new logic that handles Equals matchers differently.


1676-1687: LGTM! Location interface additions align with usage.

The expanded Location interface correctly includes fields that are already being used in the LocationCard component (e.g., mainPhone, yextDisplayCoordinate, ref_listings). This appears to be a type alignment change to match the actual data structure.


712-723: LGTM! Equals matcher handling is correct.

The implementation correctly handles Equals filters by using the filter value directly without radius augmentation. This is appropriate for non-geographic static filters like countryCode: {$eq: "US"} that don't have spatial components.

benlife5
benlife5 previously approved these changes Nov 5, 2025
When searching for countries in the locator filtersearch bar (e.g. "United States"), the static filter returned by filtersearch is
{
  "address.countryCode": {
    "$eq": "US"
  }
}
instead of a {"$near": {lat, lng, radius}} filter. This adds handling to the locator to support this type of filter, and also updates distance and clear filters click handlers to only update near filter radii.

J=WAT-5171
TEST=manual

jam:https://jam.dev/c/04a22a5c-4d95-4d89-9e31-3f7f0bc1ed0a
Mistakenly used || instead of &&
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/visual-editor/src/components/Locator.tsx (1)

711-747: Well-structured matcher handling with switch statement.

The switch-based branching cleanly separates Near and Equals filter logic. The Near path correctly derives nearFilterValue and augments radius, while the Equals path uses filter.value directly for non-location filters.

Consider adding a type guard before casting to NearFilterValue on line 713 for additional runtime safety:

     case Matcher.Near: {
       nearFilterValue = filter.value as NearFilterValue;
+      if (!nearFilterValue.lat || !nearFilterValue.lng) {
+        console.error('Invalid NearFilterValue: missing lat/lng', filter);
+        return;
+      }

Also consider more graceful error handling on line 746 instead of throwing, which could crash the component:

     default:
-      throw new Error(`Unsupported matcher type: ${filter.matcher}`);
+      console.error(`Unsupported matcher type: ${filter.matcher}. Skipping filter.`);
+      return;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 667dd05 and c814f44.

📒 Files selected for processing (1)
  • packages/visual-editor/src/components/Locator.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.
📚 Learning: 2025-10-29T22:00:03.843Z
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.

Applied to files:

  • packages/visual-editor/src/components/Locator.tsx
🔇 Additional comments (5)
packages/visual-editor/src/components/Locator.tsx (5)

752-756: LGTM: Conditional map centering for Near filters.

The conditional update correctly handles the case where Equals filters don't have lat/lng coordinates. The map center only updates when nearFilterValue contains valid location data from Near-based filters.


971-1003: LGTM: Distance updates correctly target Near-based location filters.

The handler appropriately segments filters using isLocationNearFilter, updating only Near-based location filters with the new radius while preserving other static filters (including Equals-based location filters). The fallback logic for lat/lng coordinates is defensive and handles edge cases well.


1015-1067: LGTM: Clear filters correctly resets Open Now and location Near filters.

The logic properly identifies unaffected filters using the && operator (correctly fixed from the previous review). It appropriately resets Open Now filters to unselected and location Near filters to default radius, while preserving other static filters. The single setStaticFilters call avoids race conditions from asynchronous state updates.


1698-1704: LGTM: Clean predicate helpers for filter identification.

The helper functions isLocationNearFilter and isOpenNowFilter are well-designed single-responsibility predicates. isLocationNearFilter correctly identifies Near-based location filters by checking both the field ID and matcher type, ensuring Equals-based location filters are not incorrectly matched.


1706-1717: LGTM: Location interface expansion aligns with usage.

The added fields (id, mainPhone, neighborhood, slug, yextDisplayCoordinate, ref_listings) match the actual data accessed in the LocationCard component. This type-only change properly documents the location data structure without introducing runtime changes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/visual-editor/src/components/Locator.tsx (2)

707-756: Good refactor to support multiple matcher types, but consider type validation.

The switch statement cleanly separates Near and Equals matcher handling. However, there's a potential type safety issue in the Equals case (lines 733-743): filter.value is used directly without runtime validation. If an unexpected value type is passed, this could lead to issues downstream.

Consider adding a type guard or validation, especially since this is coming from an external filter search response.

Additionally, note that map centering (lines 752-756) only occurs for Near filters with coordinates. For Equals filters (e.g., country code), the map position remains unchanged. This appears intentional but might be worth documenting if not obvious to future maintainers.

     case Matcher.Equals:
+      // Note: Equals filters (e.g., country code) don't have coordinates for map centering
       locationFilter = {
         displayName: newDisplayName,
         selected: true,
         filter: {
           kind: "fieldValue",
           fieldId: filter.fieldId,
           value: filter.value,
           matcher: Matcher.Equals,
         },
       };
       break;

1698-1704: Consider adding matcher check to isOpenNowFilter for precision.

isLocationNearFilter correctly checks both the field ID and matcher type. However, isOpenNowFilter only checks the field ID without verifying the matcher is Matcher.OpenAt.

While this is likely fine in practice (hours field probably only used for OpenAt), adding the matcher check would make the function more precise and self-documenting:

 const isOpenNowFilter = (filter: SelectableStaticFilter) =>
-  filter.filter.kind === "fieldValue" && filter.filter.fieldId === HOURS_FIELD;
+  filter.filter.kind === "fieldValue" && 
+  filter.filter.fieldId === HOURS_FIELD &&
+  filter.filter.matcher === Matcher.OpenAt;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 667dd05 and c814f44.

📒 Files selected for processing (1)
  • packages/visual-editor/src/components/Locator.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.
📚 Learning: 2025-10-29T22:00:03.843Z
Learnt from: mkouzel-yext
Repo: yext/visual-editor PR: 833
File: packages/visual-editor/src/components/Locator.tsx:1050-1057
Timestamp: 2025-10-29T22:00:03.843Z
Learning: In packages/visual-editor/src/components/Locator.tsx, the AppliedFilters component is intentionally rendered in two locations (inside the filter modal and outside it) as per the design requirements. This dual rendering should not be flagged as a duplicate issue.

Applied to files:

  • packages/visual-editor/src/components/Locator.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: call_unit_test / unit_tests (20.x)
🔇 Additional comments (3)
packages/visual-editor/src/components/Locator.tsx (3)

971-1003: LGTM: Clean filter separation and update logic.

The refactor using isLocationNearFilter improves clarity. The logic correctly separates location near filters from others, updates only the near filters with the new radius, and preserves coordinates with appropriate fallbacks.


1015-1067: LGTM: Correct filter reset logic with race condition mitigation.

The implementation correctly:

  • Uses && to exclude both Open Now and location near filters from unaffected filters
  • Updates both filter types in a single setStaticFilters call to avoid race conditions
  • Conditionally resets radius based on showDistanceOptions

1706-1717: LGTM: Interface expansion aligns with component usage.

The added fields match the actual usage in LocationCard (e.g., mainPhone at line 1359, ref_listings at line 1369, yextDisplayCoordinate at line 1382). This brings the type definition in sync with the runtime data.

@benlife5 benlife5 merged commit b3dc19e into main Nov 5, 2025
15 checks passed
@benlife5 benlife5 deleted the handle-equals-filters-locator branch November 5, 2025 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants